哇塞,有好吃的~

手撸一个简单的滑块验证码

使用过很多次滑块验证码的功能,偶然一次想起来,能不能简单的实现一个呢,于是就尝试了一下,然后记录下来了,图个乐子。

思路

  • 首先是绘制一张图片,自然而然,要用canvas了,就像下面这样,首先加载一张图片,然后去绘制到canvas中。
<div id="validate"> <canvas id="canvas"></canvas> </div> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); // 加载图片 const loadImage = (url) => { return new Promise((resolve, reject) => { const image = new Image(); image.src = url; image.crossOrigin = 'anonymous'; image.onload = () => { resolve(image); }; image.onerror = () => { reject(); } }); }; const renderImage = (image) => { const w = image.width; const h = image.height; canvas.width = w; canvas.height = h; ctx.drawImage(image, 0, 0, w, h); return [w, h]; }; // 函数入口 const start = () => { loadImage(url).then(renderImage).catch(() => { console.log('图片加载失败'); }); }; start(); </script>
  • 接下来呢,肯定就是扣出一块区域了,把原图的区域清空,然后把该区域转化成一张新的可拖拽的图片。
const clipImage = () => { // 设置滑块的宽高 const dw = 50; const dh = 50; // 随机生成空缺的x坐标 const x = Math.floor(Math.random() * (w - 2 * dw) + dw); // y坐标就固定在中间 const y = (h - dh) / 2; // 获取到这块区域的ImageData对象 const imageData = ctx.getImageData(x, y, dw, dh); // 清空这块区域 ctx.clearRect(x, y, dw, dh); // 使用一个临时的canvas承载这个ImageData去生成滑块图片 let avatarCanvas = document.createElement("canvas"); avatarCanvas.width = dw; avatarCanvas.height = dh; let avatarCtx = avatarCanvas.getContext("2d"); avatarCtx.putImageData(imageData, 0, 0); let avatarDataUrl = avatarCanvas.toDataURL(); const img = document.createElement('img'); img.src = avatarDataUrl; img.style.top = `${y}px`; img.style.left = 0; // 图片可以拖拽 img.draggable = true; // 挂载到页面上,样式使用绝对定位固定到最左侧的中间位置 validate.appendChild(img); return [img, x]; }
  • 最后呢,就处理一下图片的滑动事件,每次拖动的时候去修改img的left值,然后结束的时候就判断一下距离之前的随机x是否在一个可接受范围内就ok了。这个地方有一个注意点,就是图片拖拽的时候,默认会出现一个阴影,和原图片一样,会感觉很丑,可以设置一个空标签来隐藏这个阴影。
const handlerDrag = (img, x) => { let startX = 0; img.ondragstart = (e) => { startX = e.pageX; // // create an empty element dragElement = document.createElement("span"); dragElement.innerHTML = "&nbsp;"; dragElement.style.position = "absolute"; dragElement.style.left = "-1000%"; // add the element to the dom document.body.appendChild(dragElement); //set it as the drag image event.dataTransfer.setDragImage(dragElement, 0, 0); } img.ondrag = (e) => { if (e.pageX === 0) { return; } const deltaX = e.pageX - startX; img.style.left = `${deltaX}px`; }; img.ondragend = (e) => { const deltaX = e.pageX - startX; if(Math.abs(deltaX - x) < 50) { alert('验证成功'); } else { alert('验证失败'); } img.draggable = false; } }
  • 最后把之前的代码整合一下,其实就是在初始方法中去以此调用就好了。
const start = () => { loadImage(url).then(image => { // 这个地方是不是很眼熟,上一个函数的执行结果,是下一个函数的参数,这个大家有兴趣的可以试试,实现一个compose函数了,类似compose: (fns: Array<(arg1, arg2...) => Array<any>) => any; const [w, h] = renderImage(image); const [img, x] = clipImage(w, h); handlerDrag(img, x); }).catch(() => { console.log('图片加载失败'); }); };

效果图

start.png

end.jpg

小结

最后呢,我想说的是,这个肯定还有很多优化的地方,仅仅是提供一种实现思路,代码上也有更精简的写法,欢迎大家交流学习。


__EOF__

本文作者风行者夜色
本文链接https://www.cnblogs.com/aloneMing/p/17316108.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   风行者夜色  阅读(129)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示