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

说在前面

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

效果展示

体验地址

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

相关推荐
Z***258030 分钟前
JavaScript在Node.js中的Deno
开发语言·javascript·node.js
weixin79893765432...30 分钟前
Vue + Express + DeepSeek 实现一个简单的对话式 AI 应用
vue.js·人工智能·express
高级程序源43 分钟前
springboot社区医疗中心预约挂号平台app-计算机毕业设计源码16750
java·vue.js·spring boot·mysql·spring·maven·mybatis
cypking1 小时前
Vue 3 + Vite + Router + Pinia + Element Plus + Monorepo + qiankun 构建企业级中后台前端框架
前端·javascript·vue.js
San30.1 小时前
ES6+ 新特性解析:让 JavaScript 开发更优雅高效
开发语言·javascript·es6
雨雨雨雨雨别下啦2 小时前
【从0开始学前端】vue3简介、核心代码、生命周期
前端·vue.js·vue
simon_93492 小时前
受够了压缩和收费?我作为一个码农,手撸了一款无限容量、原图直出的瀑布流相册!
前端
e***87702 小时前
windows配置永久路由
android·前端·后端
u***27613 小时前
TypeScript 与后端开发Node.js
javascript·typescript·node.js
星空的资源小屋3 小时前
跨平台下载神器ArrowDL,一网打尽所有资源
javascript·笔记·django