纯前端实现滑动拼图验证码

www.jswusn.com JS 2025-07-26 09:47:38 9次浏览

前言

在日常应用中,验证码是防止恶意攻击的重要手段。其中滑动拼图验证码的用户体验更好。

本文将详细介绍如何仅使用HTML、CSS和JavaScript实现一个纯前端的滑动拼图验证码功能,无需后端支持即可完成验证。

1. 实现效果和思路

1.1 效果展示

1.2 实现思路

我们实现的滑动拼图验证码包含两个主要部分:

  1. 验证区域

    :显示一张背景图片,其中有一个半透明的方形缺口(目标位置)和一个可以滑动的拼图块
  2. 滑动条区域

    :包含一个可拖动的滑块和操作提示

用户需要通过拖动滑块将拼图块移动到正确位置(与缺口重合)来完成验证。如果位置准确(误差在2像素内),则验证成功;否则滑块和拼图块会复位,用户可以重新尝试。

具体流程如下:

3687ed30da76ceee54da763b5dc2009f.png

2. 代码实现

下面具体实现,代码实现主要分为三个部分:

  1. 布局结构

    :使用HTML创建验证区域和滑动条区域的基本结构
  2. 样式设计

    :使用CSS定位验证缺口和拼图块,确保拼图块能正确显示背景图片的对应部分
  3. 交互逻辑

    :通过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!


技术分享

苏南名片

  • 联系人:吴经理
  • 电话:152-1887-1916
  • 邮箱:message@jswusn.com
  • 地址:江苏省苏州市相城区

热门文章

Copyright © 2018-2025 jswusn.com 版权所有

技术支持:苏州网站建设  苏ICP备18036849号