图片滑块验证功能很难吗?做个可以自己扣形状的图片滑块验证组件

说在前面

在当今数字化世界中,网络安全和用户验证变得至关重要。随着恶意机器人和自动化攻击的增加,传统的验证码系统已经不再足够保障网站的安全性。为了提高用户体验和防止恶意攻击,图片滑块验证成为了一个热门的选择。今天,我们一起来实现一个可以自己扣形状的图片滑块验证组件

效果展示

体验地址

jyeontu.xyz/jvuewheel/#...

实现步骤

一、使用canvas展示背景图片

首先我们应该先了解一下怎么在canvas上绘制图片:

  • 1.获取Canvas元素和2D上下文:首先获取到需要绘制图片的Canvas元素,并从中获取2D上下文(Context)。可以使用以下代码获取Canvas元素和2D上下文:
javascript 复制代码
const canvas = document.getElementById('myCanvas'); // 获取Canvas元素
const ctx = canvas.getContext('2d'); // 获取2D上下文
  • 2.创建Image对象并设置src:创建一个Image对象,然后设置其src属性为要绘制的图片的URL。确保图片加载完成后再进行绘制操作。
javascript 复制代码
const image = new Image();
image.onload = function() {
  // 在图片加载完成后进行绘制操作
};
image.src = 'path_to_your_image.jpg'; // 设置图片路径
  • 3.绘制图片,在图片加载完成后,可以使用ctx.drawImage()方法在Canvas上绘制图片。
javascript 复制代码
image.onload = function() {
  ctx.drawImage(image, x, y, width, height); // 在Canvas上绘制图片
};

在上面的代码中,x和y表示图片在Canvas上的起始坐标,width和height表示图片的宽度和高度。

二、背景图片抠出滑块缺口

1、获取到canvas元素和2D上下文ctx

javascript 复制代码
const canvas = this.$refs.canvas;
const ctx = canvas.getContext("2d");

2、创建一个image对象,将图片绘制到canvas上

在图片加载完成后,函数设置了图片的宽度和高度,并将canvas的宽度和高度设置为与图片相同,然后通过ctx.drawImage()方法绘制图片。

javascript 复制代码
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、根据抠图路径,将区域镂空

这里的镂空区域我们可以设置为透明,也可以填充上我们自己喜欢的颜色。

javascript 复制代码
// 创建镂空区域的路径
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

javascript 复制代码
const canvas = this.$refs.canvas2;
const ctx = canvas.getContext("2d");

2、创建一个image对象,将图片绘制到canvas上

在图片加载完成后,函数设置了图片的宽度和高度,并将canvas的宽度和高度设置为与图片相同。

javascript 复制代码
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上。

javascript 复制代码
// 定义剪切路径
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],如下图:

javascript 复制代码
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,最后判断滑块滑动的距离是否在误差范围里即可,具体代码如下:

javascript 复制代码
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实现一个锚点抠图功能》,看过这篇文章的同学可能记得我在里面留了一个坑,现在就把它填上,我们可以利用这个工具来获取到我们自定义的滑块形状路径:

工具地址:jyeontu.xyz/JDemo/#/img...

如上图,我们现在的滑块形状也是通过这个工具获取到的,我们也可以做成下面这些样子的:

总之就是想要什么形状都可以自己抠出来,当然,喜欢直接算坐标的直接算也可以

2、注意

抠图注意将宽高设置为与组件宽高一致,不然滑块大小可能会和你想象中的不一样

源码地址

gitee

gitee.com/zheng_yongt...

公众号

关注公众号『前端也能这么有趣』发送 组件库即可获取源码。

组件使用

目前该组件库已经发布到npm,除了图片滑块验证之外还有其他许多好玩的组件,后续会继续维护,源码也已经开源,感兴趣的朋友可以瞧瞧,觉得有点意思的可以顺手点个star

组件文档:jyeontu.xyz/jvuewheel/#...

组件仓库:gitee.com/zheng_yongt...

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

相关推荐
迷雾漫步者8 分钟前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-36 分钟前
验证码机制
前端·后端
燃先生._.2 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖3 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235243 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240253 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar4 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人4 小时前
前端知识补充—CSS
前端·css
GISer_Jing4 小时前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试