前端图形学实战∶ 从零开发一款轻量级滑动验证码组件(vue3 + vite版)
本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究
前言hello, 大家好, 我是徐小夕, 今天又到了我们的博学时间。
本文是100+前端几何学应用案例专栏的第五篇文章, 之前和大家分享了如何从零实现几何画板以及几何画板的撤销 / 重做 / 图层管理等功能:
几何学在前端边界计算中的应用和原理分析前端图形学实战: 从零开发几何画板(vue3 + vite版)前端图形学实战: 100行代码实现几何画板的撤销重做等功能(vue3 + vite版)前端图形学实战: 从零实现编辑器的图层管理面板和实时缩略图(vue3 + vite版)今天和大家分享一个新的图形学实战——滑动验证码的实现。
你将收获vue3组件的设计思路和技巧canvas的常用绘图api用法滑动验证码组件的基本设计原理和实现过程如何从零发布vue3组件库
正文这篇文章我会带大家使用vue3 + vite来实现滑动验证码, 当然笔者之前也实现了基于react的滑动验证码组件, 感兴趣的可以参考我之前的文章:
从零开发一款轻量级滑动验证码插件同时也可以在github上查看到对应的实现代码:
https://github.com/MrXujiang/vue-slider-vertify
技术实现在着手开发组件之前我们需要提前明确组件的设计需求, 并制定合理的开放api, 这里分享一下我总结的组件优雅设计的原则:
可读性(代码格式统一清晰,注释完整,代码结构层次分明,编程范式使用得当)
可用性(代码功能完整,在不同场景都能很好兼容,业务逻辑覆盖率)
复用性(代码可以很好的被其他业务模块复用)
可维护性(代码易于维护和扩展,并有一定的向下/向上兼容性)
高性能(组件具有一定的性能, 如复杂场景的渲染, 计算等)
而我们滑动验证码组件要想让更多的人使用, 就必须做到一定程度的灵活可配置, 接下来是我总结的滑动验证码的核心api:
控制滑动验证码的显示隐藏(visible)控制滑动验证码的大小(width 和 height)控制滑块的样式(边长 l 和半径 r)滑块的提示文本(text)滑动验证码的图片数据源(imgUrls)验证成功的事件回调(onSuccess)验证失败的事件回调(onFail)用户自定义的验证逻辑(onCustomVertify)用户拖拽滑块时的回调(onDraw)刷新图片时的回调(onRefresh)对应图示如下:
image.png属性功能设计好之后我们来构想一下在vue项目中具体的使用方式:
template
div
vertify
width="200"
height="80"
l="50"
r="5"
/vertify
/div
/template
scriptsetup
//业务逻辑...
/script
以上基础准备好之后我们来可看一下滑动验证码的具体交互流程:
image.png1.设计滑动验证码的基本骨架这里我以vue3组合函数的方法来定义一下vue-slider-veritfy组件骨架:
script lang="ts" setup
import { ref, watch, onMounted } from "vue";
interface VertifyType {
spliced: boolean;
verified: boolean; // 简单验证拖动轨迹,为零时表示Y轴上下没有波动,可能非人为操作
left: number; // 滑块的移动位置
destX: number; // 滑块的目标位置
}
interface IProps {
width?: number;
visible?: boolean;
height?: number;
refreshIcon?: string;
l?: number;
r?: number;
imgUrl?: string;
text?: string;
/**
* @description 拖拽滑块时的回调, 参数为当前滑块拖拽的距离
* @default (l: number):void = {}
*/
onDraw?: (l: number) =
/**
* @description 用户的自定义验证逻辑
* @default (arg: VertifyType) = VertifyType
*/
onCustomVertify?: (arg: VertifyType) = VertifyType;
/**
* @description 重制刷新前的回调
* @default ():void = {}
*/
onBeforeRefresh?: () =
/**
* @description 验证成功回调
* @default ():void = {}
*/
onSuccess?: VoidFunction;
/**
* @description 验证失败回调
* @default ():void = {}
*/
onFail?: VoidFunction;
/**
* @description 刷新时回调
* @default ():void = {}
*/
onRefresh?: VoidFunction;
}
// 定义默认值
const props = withDefaults(definePropsIProps(), {
width: 320,
visible: true,
height: 160,
refreshIcon: "http://cdn.dooring.cn/dr/icon12.png",
l: 42,
r: 9,
imgUrl: "",
text: "",
});
// 构建dom结构
template
div
className="vertifyWrap"
div className="canvasArea"
canvas ref="canvasRef"/canvas
/div
div
:className="sliderClass"
div className="sliderMask"
div
className="slider"
div className="sliderIcon"/div
/div
/div
div className="sliderText"{{ textTip }}/div
/div
div
className="refreshIcon"
/div
div
className="loadingContainer"
div className="loadingIcon"/div
span加载中.../span
/div
/div
/template
上面代码需要注意的就是withDefaults和defineProps,defineProps主要用来定义vue组件的属性类型,withDefaults可以用来定义组件属性的默认值, 这也是在设计vue3组件中常用的api。
2. 滑动验证码核心功能实现接下来我们需要实现以下几个核心功能:
镂空效果的canvas图片实现镂空图案canvas实现滑块移动和验证逻辑实现上面的描述可能比较抽象,我画张图示意一下:
image.png在开始编码之前我们需要对canvas有个基本的了解,建议不熟悉的朋友可以参考高效canvas学习文档: Canvas of MDN。
由上图可知首先要解决的问题就是如何用canvas画不规则的图形,这里我简单的画个草图:
image.png我们只需要使用canvas提供的路径api画出上图的路径,并将路径填充为任意半透明的颜色即可。建议大家不熟悉的可以先了解如下api:
beginPath() 开始路径绘制moveTo() 移动笔触到指定点arc() 绘制弧形lineTo() 画线stroke() 描边fill() 填充clip() 裁切路径由于实现方式比较固定, 偏canvas语法层, 这里直接分享一下代码:
constdrawPath=(ctx:any,x:number,y:number,operation:"fill"|"clip")={
ctx.beginPath();
ctx.moveTo(x,
ctx.arc(x+l/2,y-r+2,r,0.72*PI,2.26*
ctx.lineTo(x+l,
ctx.arc(x+l+r-2,y+l/2,r,1.21*PI,2.78*
ctx.lineTo(x+l,y+
ctx.lineTo(x,y+
ctx.arc(x+r-2,y+l/2,r+0.4,2.76*PI,1.24*PI,true);
ctx.lineTo(x,
ctx.lineWidth=2;
ctx.fillStyle="rgba(255,255,255,0.7)";
ctx.strokeStyle="rgba(255,255,255,0.7)";
ctx.stroke();
ctx.globalCompositeOperation="destination-over";
operation==="fill"?ctx.fill():ctx.clip();
};
这里需要补充的一点是canvas的globalCompositeOperation属性,它的主要目的是设置如何将一个源(新的)图像绘制到目标(已有)的图像上。
源图像 = 我们打算放置到画布上的绘图
目标图像 = 我们已经放置在画布上的绘图
w3c上有个形象的例子:
image.png这里之所以设置该属性是为了让镂空的形状不受背景底图的影响并覆盖在背景底图的上方。如下:
image.png接下来我们只需要将图片绘制到画布上即可:
constcanvasCtx=canvasRef.current.getContext('2d')
//绘制镂空形状
drawPath(canvasCtx,50,50,'fill')
//画入图片
canvasCtx.drawImage(img,0,0,width,height)
接下来我们只需要用javascript实现随机图片和随机位置即可。
我们再来实现一下镂空效果:
constblockCtx=blockRef.value.getContext('2d')
drawPath(blockCtx,50,50,'clip')
blockCtx.drawImage(img,0,0,width,height)
//提取图案滑块并放到最左边
consty1=50-r*2-1
constImageData=blockCtx.getImageData(xRef.value-3,y1,L,L)
//调整滑块画布宽度
blockRef.value.width=L
blockCtx.putImageData(ImageData,0,y1)
上面的代码我们用到了getImageData和putImageData,这两个api主要用来获取canvas画布场景像素数据和对场景进行像素数据的写入。实现后 的效果如下:
image.png实现滑块移动和验证逻辑
实现滑块移动的方案也比较简单,我们只需要利用鼠标的event事件即可:
onMouseDownonMouseMoveonMouseUpimage.png以上是一个简单的示意图,具体实现代码如下:
consthandleDragMove=(e)={
if(!isMouseDownRef.value)returnfalse
e.preventDefault()
//为了支持移动端,可以使用e.touches[0]
consteventX=e.clientX||e.touches[0].clientX
consteventY=e.clientY||e.touches[0].clientY
constmoveX=eventX-originXRef.value
constmoveY=eventY-originYRef.value
if(moveX0||moveX+36=width)returnfalse
sliderLeft.value=moveX;
constblockLeft=(width-l-2r)/(width-l)*moveX
blockRef.value.style.left=blockLeft+'px'
}
当然我们还需要对拖拽停止后的事件做监听,来判断是否验证成功,并埋入成功和失败的回调。
我们发现vue3版本的实现和我之前的react版本的方式类似, 主要区别就在于api用法和定义上, 这里分享一下具体的变量定义:
const{
text,
l,
r,
imgUrl,
width,
height,
visible,
onBeforeRefresh,
onRefresh,
onFail,
onSuccess,
onCustomVertify,
onDraw,
}=props;
constisLoading=ref(false);
constsliderLeft=ref(0);
constsliderClass=ref("sliderContainer");
consttextTip=ref(text);
constcanvasRef=refany(null);
constblockRef=refany(null);
constimgRef=refany(null);
constisMouseDownRef=refboolean(false);
consttrailRef=refnumber[]
constoriginXRef=refnumber(0);
constoriginYRef=refnumber(0);
constxRef=refnumber(0);
constyRef=refnumber(0);
constPI=Math.PI;
constL=l+r*2+3;//滑块实际边长
将实现的滑动验证码组件发布到 npm 上
发布流程我在从零开发一款轻量级滑动验证码插件有详细的介绍, 接下来给大家展示一下通过vite打包组件包的配置:
exportdefaultdefineConfig({
...baseConfig,
build:{
outDir:'dist',
lib:{
entry:resolve(__dirname,'../packages/index.ts'),
name:'vue-slider-vertify',
fileName:(format)=`vue-slider-vertify.${format}.js`,
},
rollupOptions:{
//确保外部化处理不想打包进库的依赖
external:['vue'],
output:{
//在UMD构建模式下为这些外部化的依赖提供一个全局变量
globals:{
vue:'Vue'
}
}
}
},
plugins:[
...(baseConfigasany).plugins,
dts(),
]
});
打包后的dist目录结构如下:
image.png如果大家想了解详细的源码和打包过程, 可以在github上查看完整代码, 地址如下:
https://github.com/MrXujiang/vue-slider-vertify
如果大家想通过 npm 的方式直接使用, 可以用我已经发布到npm服务器的react-slider-vertify, 按照如下方式安装和使用:
#或者npmadd@alex_xu/react-slider-vertify
yarnadd@alex_xu/react-slider-vertify
在代码里使用:
importReactfrom'react';
import{Vertify}from'@alex_xu/react-slider-vertify';
exportdefault()={
returnVertify
width={320}
height={160}
onSuccess={()=alert('success')}
onFail={()=alert('fail')}
onRefresh={()=alert('refresh')}
/
};
image.png扩展大家也可以基于自己的业务需求改造我们的验证码, 实现更负复杂的功能, 改造成多种形态的验证码, 也欢迎大家随时贡献, 一起打造非常有意思的验证码组件。
后期规划后面会继续围绕图形可视化来实现更多有意思的应用, 比如3D可视化, 图形编辑器, 可视化图表等, 如果大家感兴趣, 可以参考我的github: https://gitee.com/lowcode-china/euryd
如果文章对你有帮助, 欢迎点赞评论, 让我们一起探索真正的前端技术。
更多推荐(10月最新) 前端图形学实战: 从零开发几何画板(vue3 + vite版)
Dooring无代码搭建平台技术演进之路[1]
从零开发一款可视化大屏制作平台[2]
从零开发一款图片编辑器Mitu[3]
[1]https://juejin.cn/post/7114324484399562766:https://juejin.cn/post/7114324484399562766
[2]https://juejin.cn/post/6937257727106220040:https://juejin.cn/post/6937257727106220040
[3]https://juejin.cn/post/6997586040835801118:https://juejin.cn/post/6997586040835801118
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线