实现拼图滑动验证码

实现拼图滑动验证码

拼图滑动验证码的纯前端简单实现,重要部分都已标注注释,如果需要配合后端可以参考此思路,后端处理图片生成一个带缺口的背景图与一个符合缺口的拼图,并将取得拼图块的位置记录到SESSION,将图片与拼图传给前端展示,当用户拖动并松开鼠标后将鼠标轨迹与停留位置发送到后端,后端从SESSION中取得位置信息并与前端传递的位置进行对比,有需要的话可以分析此用户轨迹用以区分人机,如果位置偏差小于一定阈值则认为拼图成功。

实例#

Copy
<!DOCTYPE html> <html> <head> <title>滑动拼图验证码</title> <link rel="stylesheet" type="text/css" href="https://at.alicdn.com/t/font_1582902_u0zm91pv15i.css"> <style type="text/css"> .verify-slide-con{ /* 滑动拼图容器块 */ width: 360px; padding: 10px 20px; border: 1px solid #eee; } .img-con{ /* 图片容器块 */ width: 100%; height: 200px; display: flex; justify-content: center; align-items: center; overflow: hidden; border: 1px solid #eee; position: relative; } .img-con > .slide-block{ /* 图片区域的滑块 */ top: 0; left: 0; position: absolute; height: 40px; width: 40px; display: none; background-repeat: no-repeat; background-attachment: scroll; background-size: 360px 200px; z-index: 10; box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.4), 0 0 10px 0 rgba(90, 90, 90, 0.4); } .img-con > .slide-block-mask{ /* 图片区域的空缺区域 */ top: 0; left: 0; position: absolute; height: 40px; width: 40px; display: none; background-color: rgba(0, 0, 0, 0.4); } .img-con > .img{ /* 图片 */ width: 100%; height: 100%; } .img-con > .loading{ /* 加载中样式 */ width: unset; height: unset; } .slide-con{ /* 滑块容器 */ height: 40px; margin: 10px 0; position: relative; border: 1px solid #eee; } .slide-con > .slide-btn{ /* 滑动按钮 */ height: 40px; width: 40px; position: absolute; background: #4C98F7; display: flex; justify-content: center; align-items: center; cursor: pointer; } .icon-arrow-right{ /* 右箭头 */ font-size: 30px; color: #fff; } .operate-con{ /* 操作容器块 */ border-top: 1px solid #eee; height: 30px; padding: 5px 0 0 5px; display: flex; align-items: center; } .icon-shuaxin1{ /* 刷新按钮 */ color: #777; font-size: 20px; cursor: pointer; } </style> </head> <body> <div class="verify-slide-con"> <!-- 滑动拼图容器块 --> <div class="img-con"> <!-- 图片容器块 --> <img class="img"> <!-- 图片 --> <div class="slide-block"></div> <!-- 拼图 --> <div class="slide-block-mask"></div> <!-- 缺口 --> </div> <div class="slide-con"> <!-- 滑块容器 --> <div class="slide-btn"> <!-- 滑动按钮 --> <i class="iconfont icon-arrow-right"></i> <!-- 图标 --> </div> </div> <div class="operate-con"> <!-- 操作容器块 --> <i id="refresh" class="iconfont icon-shuaxin1"></i> <!-- 刷新按钮 --> </div> </div> </body> <script type="text/javascript"> (function(){ var imgList = [ // 图片组 "http://www.sdust.edu.cn/__local/9/7A/B1/F29B84DEF72DD329997E8172ABA_664BA3EF_32466.jpg", "http://www.sdust.edu.cn/__local/B/F3/E4/693AB931C9FFB84646970D53BFE_C506394A_4282CA.jpg", "http://www.sdust.edu.cn/__local/F/7A/AA/E1459849AA8AB0C89854A41BD41_BF3BD857_BC0D8.jpg", "http://www.sdust.edu.cn/__local/1/95/CB/EDC1450B8FD1B8A25FAAC726AA4_A36D4253_16C91.jpg", ]; var imgCon = document.querySelector(".img-con"); // 图片容器元素引用 var img = document.querySelector(".img-con > .img"); // 图片元素引用 var slideBlock = document.querySelector(".img-con > .slide-block"); // 滑块元素引用 var slideBlockMask = document.querySelector(".img-con > .slide-block-mask"); // 缺口元素引用 var slideCon = document.querySelector(".slide-con"); // 滑动容器引用 var slideBtn = document.querySelector(".slide-con > .slide-btn"); // 滑块按钮引用 var refreshBtn = document.querySelector("#refresh"); // 刷新按钮引用 function randomInt(min=0, max=1) { // 生成随机数 return min + ~~((max-min)*Math.random()) // min <= random < max } function initSlider(){ var maxTop = imgCon.offsetHeight - ~~(window.getComputedStyle(slideBlock).getPropertyValue("height").replace("px","")); // 获取最大Y轴偏移距离 var maxRight = imgCon.offsetWidth - ~~(window.getComputedStyle(slideBlock).getPropertyValue("width").replace("px","")); // 获取最大X轴偏移距离 var randPosY = randomInt(0, maxTop); // 随机Y轴偏移 var randPosX = randomInt(60, maxRight); // 随机X轴偏移 slideBtn.onmousedown = function(e){ slideBlock.style.display = "block"; // 显示拼图 slideBlock.style.top=`${randPosY}px`; // 拼图Y轴偏移 slideBlock.style["background-position"] = `-${randPosX}px -${randPosY}px`; // 指定背景图位置 slideBlockMask.setAttribute("style", `display:block;top:${randPosY}px;left:${randPosX}px`); // 显示缺口并指定位置 var edgeX = e.clientX; // 鼠标点击位置 document.onmousemove = event => { var relativeX = event.clientX - edgeX; // 鼠标移动距离 if(relativeX<0 || relativeX>imgCon.offsetWidth-this.offsetWidth) return void 0; // 判断是否超出滑动容器块 超出则不移动 slideBlock.style.left = relativeX + "px"; // 移动拼图 this.style.left = relativeX + "px"; // 移动滑块按钮 } document.onmouseup = function() { this.onmousemove = null; // 撤销事件 this.onmouseup = null; // 撤销事件 if(Math.abs(slideBlock.offsetLeft - slideBlockMask.offsetLeft)<=2) alert("验证成功"); // 偏移距离小于2则认为成功 else alert("验证失败"); // 否则失败 slideBlock.style.left = 0; // 拼图归位 slideBtn.style.left = 0; // 滑块按钮归位 }; } } function switchImg(){ slideBlock.style.display = "none"; // 不显示拼图 slideBlockMask.style.display = "none"; // 不显示缺口 img.classList.add("loading"); // 指定图片加载中样式 img.src="https://cdn.jsdelivr.net/gh/sentsin/layui@15d7241/dist/css/modules/layer/default/loading-2.gif"; // 加载动画 var newSrc = imgList[randomInt(0, 4)]; // 随机加载图片 var tmp = new Image(); // 隐式加载图片 tmp.src = newSrc; // 指定src tmp.onload = function(){ img.classList.remove("loading"); // 撤销loading img.src = newSrc; // 指定src 此时从缓存加载图片 slideBlock.style["background-image"] = `url(${newSrc})`; // 拼图背景 initSlider(); // 初始化滑块 } } (function(){ switchImg(); // 加载图片 refreshBtn.addEventListener("click", e => switchImg()); // 刷新按钮绑定事件 })(); })(); </script> </html>

每日一题#

Copy
https://github.com/WindrunnerMax/EveryDay

参考#

Copy
https://zhuanlan.zhihu.com/p/42082496 https://github.com/himushroom/verify-slide https://www.cnblogs.com/xiaoshen666/p/10968750.html
posted @   WindRunnerMax  阅读(1344)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示
CONTENTS