zoukankan      html  css  js  c++  java
  • 实现拼图滑动验证码

    实现拼图滑动验证码

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

    实例

    <!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{ /* 滑动拼图容器块 */
                 360px;
                padding: 10px 20px;
                border: 1px solid #eee;
            }
            .img-con{ /* 图片容器块 */
                 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;
                 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;
                 40px;
                display: none;
                background-color: rgba(0, 0, 0, 0.4);
            }
            .img-con > .img{ /* 图片 */
                 100%;
                height: 100%;
            }
            .img-con > .loading{ /* 加载中样式 */
                 unset;
                height: unset;
            }
            .slide-con{ /* 滑块容器 */
                height: 40px;
                margin: 10px 0;
                position: relative;
                border: 1px solid #eee;
            }
            .slide-con > .slide-btn{ /* 滑动按钮 */
                height: 40px;
                 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>
    

    每日一题

    https://github.com/WindrunnerMax/EveryDay
    

    参考

    https://zhuanlan.zhihu.com/p/42082496
    https://github.com/himushroom/verify-slide
    https://www.cnblogs.com/xiaoshen666/p/10968750.html
    
  • 相关阅读:
    界面控件DevExpress WPF入门 表达式编辑器功能
    Telerik UI for WPF全新版本——拥有Office2019高对比度主题
    DevExpress报表控件v21.2 全新的Visual Studio报表设计器
    报告生成器FastReport .NET入门指南 在Linux中启动应用程序
    文档控件DevExpress Office File API v21.2 自定义字体加载引擎
    UI组件库Kendo UI for Angular入门 如何开始使用图表功能
    WPF界面工具Telerik UI for WPF入门级教程 设置一个主题(二)
    DevExtreme初级入门教程(React篇) TypeScript支持
    报表开发利器FastReport .NET v2022.1 添加关键对象和属性
    python项目打包(一) setup.py、Python源代码项目结构
  • 原文地址:https://www.cnblogs.com/WindrunnerMax/p/13585107.html
Copyright © 2011-2022 走看看