说在前面
在当今数字化世界中,网络安全和用户验证变得至关重要。随着恶意机器人和自动化攻击的增加,传统的验证码系统已经不再足够保障网站的安全性。为了提高用户体验和防止恶意攻击,图片滑块验证成为了一个热门的选择。今天,我们一起来实现一个可以自己扣形状的图片滑块验证组件
效果展示
体验地址
http://jyeontu.xyz/jvuewheel/#/JImgVerifyView
实现步骤
一、使用canvas展示背景图片
首先我们应该先了解一下怎么在canvas上绘制图片:
- 1.获取Canvas元素和2D上下文:首先获取到需要绘制图片的Canvas元素,并从中获取2D上下文(Context)。可以使用以下代码获取Canvas元素和2D上下文:
const canvas = document.getElementById('myCanvas'); // 获取Canvas元素 const ctx = canvas.getContext('2d'); // 获取2D上下文
- 2.创建Image对象并设置src:创建一个Image对象,然后设置其src属性为要绘制的图片的URL。确保图片加载完成后再进行绘制操作。
const image = new Image(); image.onload = function() { // 在图片加载完成后进行绘制操作 }; image.src = 'path_to_your_image.jpg'; // 设置图片路径
- 3.绘制图片,在图片加载完成后,可以使用ctx.drawImage()方法在Canvas上绘制图片。
image.onload = function() { ctx.drawImage(image, x, y, width, height); // 在Canvas上绘制图片 };
在上面的代码中,x和y表示图片在Canvas上的起始坐标,width和height表示图片的宽度和高度。
二、背景图片抠出滑块缺口
1、获取到canvas元素和2D上下文ctx
const canvas = this.$refs.canvas; const ctx = canvas.getContext("2d");
2、创建一个image对象,将图片绘制到canvas上
在图片加载完成后,函数设置了图片的宽度和高度,并将canvas的宽度和高度设置为与图片相同,然后通过ctx.drawImage()方法绘制图片。
const image = new Image(); image.onload = () => { image.width = parseInt(this.width); image.height = parseInt(this.height); canvas.width = image.width; canvas.height = image.height; // 绘制图片 ctx.drawImage(image, 0, 0, canvas.width, canvas.height); }; image.src = this.imgSrc;
3、根据抠图路径,将区域镂空
这里的镂空区域我们可以设置为透明,也可以填充上我们自己喜欢的颜色。
// 创建镂空区域的路径 this.cutImg(ctx, this.cutPath, image, canvas); // 在路径内部清除像素 if (this.fillStyle) { ctx.fillStyle = this.fillStyle; // 设置填充颜色 } else { ctx.globalCompositeOperation = "destination-out"; } ctx.fill(); resolve();
然后我们就可以得到这么一张图片
三、抠出一个滑块图片
前面我们生成了一张扣出了滑块缺口的图片,那么我们还需要一张图片可以来填充这个缺口,所以我们需要再抠出一张图片
1、获取到canvas元素和2D上下文ctx
const canvas = this.$refs.canvas2; const ctx = canvas.getContext("2d");
2、创建一个image对象,将图片绘制到canvas上
在图片加载完成后,函数设置了图片的宽度和高度,并将canvas的宽度和高度设置为与图片相同。
const image = new Image(); image.onload = () => { image.width = parseInt(this.width); image.height = parseInt(this.height); canvas.width = image.width; canvas.height = image.height; …… }; image.src = this.imgSrc;
3、根据抠图路径,抠出指定区域图片
创建了一个剪切路径,如果定义了strokeStyle属性,则设置绘制路径的颜色,然后用ctx.stroke()方法绘制路径。接着,使用ctx.clip()方法将当前路径设置为剪切路径。这意味着后续绘制的所有内容都将被剪切成路径内部的形状。
最后,使用ctx.drawImage()方法将图片绘制到Canvas上。
// 定义剪切路径 this.cutImg(ctx, this.cutPath, image, canvas); if (this.strokeStyle) { ctx.strokeStyle = this.strokeStyle; } ctx.stroke(); ctx.clip(); // 绘制图片 ctx.drawImage(image, 0, 0, canvas.width, canvas.height); resolve();
然后我们就可以得到这么一张图片
四、滑动条控制滑块滑动
1、图块跟随滑动条滑动
- 初始滑动回调
使用startSliding
来标记是否初始滑动,是初始滑动时执行start
回调。 - 滑动位置计算
滑动条滑动距离 = 图片总宽度 * 当前滑动比例; - 控制图片滑块不滑出图片区域
我们假设背景图片的宽度为width
,滑块最左边的x坐标为minX
,最右端的X坐标为maxX
,那么滑块的最大宽度则为maxX - minX
,则滑块的可滑动范围应该是[0,widht - maxX + minX]
,如下图:
这样想那你就错了,滑块整个的大小其实是和原图片一样的,如下图:
所以其移动范围的计算方式应该是这样的:
还是假设背景图片的宽度为width
,滑块最左边的x坐标为minX
,最右端的X坐标为maxX
,那么滑块的最大宽度则为maxX - minX
,则滑块的可滑动范围应该是:[-minX,width - maxX]
,如下图:
onSliderChange(sliderValue) { if (!this.startSliding) { this.startSliding = true; this.$emit("start"); } const left = parseInt(this.width) * (sliderValue / 100); this.startLeft = Math.min( parseInt(this.originLeft) + parseInt(left), parseInt(this.width) - this.sliderInfo.maxX ); }
2、判断滑块结束位置是否通过
滑块和缺口完全重合的时候,滑块滑动的距离应该是0
,这里我们设置一个误差属性passDiff
,默认为3px,最后判断滑块滑动的距离是否在误差范围里即可,具体代码如下:
confirmSlider() { if (Math.abs(this.startLeft) <= this.passDiff) { this.$JToast("验证通过"); } else if (this.failedText) { this.$JToast(this.failedText); } setTimeout(() => { this.init(); }, 1000); this.startSliding = false; this.$emit("end", Math.abs(this.startLeft) <= this.passDiff); }
五、更换自己喜欢的滑块形状
1、抠图工具
默认的滑块形状是下面这样的:
如果你不喜欢的话也可以换成自己喜欢的形状,前面我分享过一篇文章《使用canvas实现一个锚点抠图功能》,看过这篇文章的同学可能记得我在里面留了一个坑,现在就把它填上,我们可以利用这个工具来获取到我们自定义的滑块形状路径:
工具地址:http://jyeontu.xyz/JDemo/#/imgCut
如上图,我们现在的滑块形状也是通过这个工具获取到的,我们也可以做成下面这些样子的:
总之就是想要什么形状都可以自己抠出来,当然,喜欢直接算坐标的直接算也可以
2、注意
抠图注意将宽高设置为与组件宽高一致,不然滑块大小可能会和你想象中的不一样
源码地址
gitee
https://gitee.com/zheng_yongtao/jyeontu-component-warehouse.git
公众号
关注公众号『前端也能这么有趣
』发送 组件库
即可获取源码。
组件使用
目前该组件库已经发布到npm,除了图片滑块验证之外还有其他许多好玩的组件,后续会继续维护,源码也已经开源,感兴趣的朋友可以瞧瞧,觉得有点意思的可以顺手点个star
组件文档:http://jyeontu.xyz/jvuewheel/#/installView
组件仓库:https://gitee.com/zheng_yongtao/jyeontu-component-warehouse.git
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣
』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。