前言
在日常应用中,验证码是防止恶意攻击的重要手段。其中滑动拼图验证码的用户体验更好。
本文将详细介绍如何仅使用HTML、CSS和JavaScript实现一个纯前端的滑动拼图验证码功能,无需后端支持即可完成验证。
1. 实现效果和思路
1.1 效果展示
1.2 实现思路
我们实现的滑动拼图验证码包含两个主要部分:
验证区域
:显示一张背景图片,其中有一个半透明的方形缺口(目标位置)和一个可以滑动的拼图块 滑动条区域
:包含一个可拖动的滑块和操作提示
用户需要通过拖动滑块将拼图块移动到正确位置(与缺口重合)来完成验证。如果位置准确(误差在2像素内),则验证成功;否则滑块和拼图块会复位,用户可以重新尝试。
具体流程如下:
2. 代码实现
下面具体实现,代码实现主要分为三个部分:
布局结构
:使用HTML创建验证区域和滑动条区域的基本结构 样式设计
:使用CSS定位验证缺口和拼图块,确保拼图块能正确显示背景图片的对应部分 交互逻辑
:通过JavaScript实现: 随机生成验证缺口位置 滑块拖拽功能 验证位置判断 成功/失败反馈
2.1 HTML结构
<divclass="check"> <divclass="check-content"></div> <divclass="check-block"></div> </div> <divclass="drag"> <divclass="drag-block"></div> <divclass="drag-tips"> 按住左边按钮向右拖动完成上方图像验证 </div> </div>
.check
:验证区域容器,包含背景图片 .check-content
:验证缺口(目标位置) .check-block
:可移动的拼图块 .drag
:滑动条区域 .drag-block
:可拖动的滑块 .drag-tips
:操作提示文字
2.2 CSS样式
.check { width: 375px; height: 250px; background-repeat: no-repeat; background-size: 100%100%; background-image: url(背景图片URL); }
验证区域设置固定宽高和背景图片,背景图片会自适应填充整个区域。
.check-content { width: 50px; height: 50px; background: rgba(0, 0, 0, 0.5); border: 1px solid #fff; position: absolute; top: 100px; left: 280px; }
验证缺口使用绝对定位,半透明黑色背景(rgba(0,0,0,0.5))和白色边框使其在背景图上可见。
.check-block { width: 50px; height: 50px; border: 1px solid #fff; background-image: inherit; background-repeat: inherit; background-size: 400px300px; background-position: -280px -100px; position: absolute; top: 100px; left: 10px; }
拼图块的关键在于background-image: inherit
继承父级的背景图片,然后通过background-position
调整显示位置,使其显示与缺口对应的背景部分。background-size
设置为原图尺寸确保图片定位准确。
.drag { width: 375px; height: 50px; background-color: #e3e3e3; margin-top: 10px; position: relative; } .drag-block { width: 50px; height: 50px; background-color: yellowgreen; z-index: 10; position: absolute; top: 0; left: 0; } .drag-tips { position: absolute; top: 0; left: 0; right: 0; text-align: center; line-height: 50px; font-size: 12px; color: #8a8a8a; }
滑动条区域使用相对简单的样式,滑块使用亮色突出显示,提示文字居中。
2.3 JavaScript交互逻辑
2.3.1 随机生成验证位置
let x = random(0, 325) let y = random(0, 200) functionrandom(min, max) { min = Math.ceil(min); max = Math.floor(max); returnMath.floor(Math.random() * (max - min) + min) }
使用random()
函数生成缺口和拼图块的随机位置,x范围0-325(考虑滑块宽度),y范围0-200。
2.3.2 设置初始位置
const checkContent = document.querySelector('.check-content') const checkBlock = document.querySelector('.check-block') checkContent.style.cssText = `left:${x}px;top:${y}px` checkBlock.style.cssText = `background-position: -${x}px -${y}px;top: ${y}px`
将验证缺口定位到随机位置,同时设置拼图块的背景位置与之对应,确保拼图块显示的是缺口位置的背景内容。
2.3.3 滑块拖拽功能
let animating = false let startX = 0 const dragBlock = document.querySelector('.drag-block') dragBlock.addEventListener('mousedown', (e) => { animating = true startX = e.pageX }) document.addEventListener('mouseup', () => { animating = false })
animating
标记拖动状态 startX
记录鼠标按下时的初始位置 鼠标按下时开始拖动,鼠标释放时结束拖动
2.3.4 拖动处理
let offsetX = 0 const drag = document.querySelector('.drag') drag.addEventListener('mousemove', (event) => { if (!animating) return offsetX = event.pageX - startX if (offsetX < 0 || offsetX > 350) { return } dragBlock.style.transform = `translateX(${offsetX}px` checkBlock.style.left = `${offsetX}px` })
计算鼠标移动距离并限制范围(0-350px),同时移动滑块和拼图块。
2.3.5 验证结果判断
drag.addEventListener('mouseup', () => { animating = false if (offsetX >= x-2 && offsetX <= x+2) { alert('成功') } else { dragBlock.style.transform = `translateX(0px)` checkBlock.style.left = `0px` } })
松开鼠标时判断滑块位置是否在目标位置的±2像素范围内,成功则提示,失败则复位。
3. 完整代码
完整代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } .check { width: 375px; height: 250px; background-repeat: no-repeat; background-size: 100%100%; background-image: url(https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimage109.360doc.com%2FDownloadImg%2F2025%2F04%2F0321%2F296122601_4_20250403090445718&refer=http%3A%2F%2Fimage109.360doc.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1753661288&t=a771e85cfd66e6e402deb166953f266e&w=750&h=500); } .check-content { width: 50px; height: 50px; background: rgba(0, 0, 0, 0.5); border: 1px solid #fff; position: absolute; top: 100px; left: 280px; } .check-block { width: 50px; height: 50px; border: 1px solid #fff; /* 直接继承父级 */ background-image: inherit; background-repeat: inherit; /* 图片的大小*/ background-size: 400px300px; /* 设置为校验区域的坐标位置 check-content的left和top */ background-position: -280px -100px; position: absolute; top: 100px; left: 10px; } .drag { width: 375px; height: 50px; background-color: #e3e3e3; margin-top: 10px; position: relative; } .drag-block { width: 50px; height: 50px; background-color: yellowgreen; z-index: 10; position: absolute; top: 0; left: 0; } .drag-tips { position: absolute; top: 0; left: 0; right: 0; text-align: center; line-height: 50px; font-size: 12px; color: #8a8a8a; } </style> </head> <body> <div class="check"> <div class="check-content"></div> <div class="check-block"></div> </div> <div class="drag"> <div class="drag-block"> </div> <div class="drag-tips"> 按住左边按钮向右拖动完成上方图像验证 </div> </div> </body> <script> //随机生成一个x , Y坐标 用于设置校验块的位置 因为滑块有50px的宽度 所以x的范围为0-325 y的范围为0-200 let x = random(0, 325) let y = random(0, 200) //随机函数 //@ param min 最小值 //@ param max 最大值 function random(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min) + min) } // 设置校验块的位置 const checkContent = document.querySelector('.check-content') const checkBlock = document.querySelector('.check-block') checkContent.style.cssText = `left:${x}px;top:${y}px` checkBlock.style.cssText = `background-position: -${x}px -${y}px;top: ${y}px` // 定义个运动状态 如果为true代表鼠标已经按下 let animating = false // 定义存储鼠标按下的x坐标 let startX = 0 // 获取拖拽的滑块 const dragBlock = document.querySelector('.drag-block') // 添加鼠标按下事件 dragBlock.addEventListener('mousedown', (e) => { animating = true startX = e.pageX }) // 添加鼠标弹起事件 document.addEventListener('mouseup', () => { animating = false }) // 存储移动的距离 let offsetX = 0 // 获取校验区域 const drag = document.querySelector('.drag') // 添加鼠标移动事件 drag.addEventListener('mousemove', (event) => { // 没有按下鼠标 不执行 if (!animating) return // 存储鼠标移动的距离 offsetX = event.pageX - startX // 限制移动的范围 0-350 if (offsetX < 0 || offsetX > 350) { return } // 修改可移动盒子的 x 轴坐标 dragBlock.style.transform = `translateX(${offsetX}px` // 设置被验证滑块left值 checkBlock.style.left = `${offsetX}px` }) drag.addEventListener('mouseup', () => { animating = false // 根据移动的位置判断是否成功 // 移动的距离和校验块的x坐标的差值小于2 代表成功 if (offsetX >= x-2 && offsetX <= x+2) { alert('成功') } else { // 验证失败 滑块和被验证块恢复坐标 dragBlock.style.transform = `translateX(0px)` checkBlock.style.left = `0px` } }) </script> </html>
3. 总结
最后总结一下,滑动拼图验证码的核心原理是在背景中生成随机的拼图块,进行拖拽匹配,如果匹配在误差合理范围内则成功,否则失败。
希望本文能对你有所帮助,如果有错误,请指正O^O!