實現拼圖滑動驗證碼


實現拼圖滑動驗證碼

拼圖滑動驗證碼的純前端簡單實現,重要部分都已標注注釋,如果需要配合后端可以參考此思路,后端處理圖片生成一個帶缺口的背景圖與一個符合缺口的拼圖,並將取得拼圖塊的位置記錄到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{ /* 滑動拼圖容器塊 */
            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>

每日一題

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM