最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何使用HTML+JavaScript實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼

 更新時(shí)間:2026年01月13日 11:29:22   作者:bjzhang75  
這篇文章主要介紹了如何使用HTML+JavaScript實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼的相關(guān)資料,通過示例代碼詳細(xì)描述了系統(tǒng)的功能實(shí)現(xiàn)、代碼結(jié)構(gòu)及擴(kuò)展建議,需要的朋友可以參考下

一、滑動(dòng)驗(yàn)證碼

在現(xiàn)代網(wǎng)絡(luò)安全體系中,人機(jī)驗(yàn)證機(jī)制扮演著至關(guān)重要的角色。傳統(tǒng)的文本驗(yàn)證碼由于識(shí)別困難、用戶體驗(yàn)差等問題逐漸被更先進(jìn)的驗(yàn)證方式取代?;瑒?dòng)驗(yàn)證碼作為一種新型的人機(jī)驗(yàn)證手段,憑借其直觀的操作體驗(yàn)和良好的安全性,廣泛應(yīng)用于各類網(wǎng)站和應(yīng)用程序中。本文將詳細(xì)介紹如何使用 HTML、CSS 和 JavaScript 構(gòu)建一個(gè)完整的滑動(dòng)驗(yàn)證碼系統(tǒng)。

二、效果演示

滑動(dòng)驗(yàn)證碼的核心交互流程包括圖像加載、拼圖生成、用戶拖拽和驗(yàn)證判斷四個(gè)階段,用戶通過拖拽右側(cè)滑塊向右移動(dòng),使拼圖塊與背景圖像中的缺口對(duì)齊,驗(yàn)證成功時(shí)顯示綠色成功提示,失敗則顯示紅色錯(cuò)誤信息并自動(dòng)重置。

三、系統(tǒng)分析

1、頁(yè)面結(jié)構(gòu)

整個(gè)滑動(dòng)驗(yàn)證碼系統(tǒng)采用簡(jiǎn)潔清晰的 HTML 結(jié)構(gòu)設(shè)計(jì),主要包括圖像顯示區(qū)(verify-img)、滑動(dòng)控制區(qū)(erify-bar-box)和結(jié)果顯示區(qū)(verify-result)三個(gè)核心部分。

<div class="verify-container">
  <div class="verify-box">
    <div class="verify-img">
      <img class="back-img" src="" style="width:100%;height:100%;"/>
      <div class="loading-indicator" id="backImgLoading" style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#666;font-size:14px;display:none;">加載中...</div>
    </div>
    <div class="verify-bar-box">
      <span class="verify-msg">向右滑動(dòng)完成驗(yàn)證</span>
      <div class="verify-left-bar"></div>
      <div class="verify-move-block">
        <span>></span>
        <div class="verify-sub-block">
          <img class="block-img" src="" style="width:100%;height:100%;"/>
        </div>
      </div>
    </div>
  </div>
  <div class="verify-result" id="verifyResult"></div>
</div>

2、核心功能實(shí)現(xiàn)

2.1 初始化流程

主要實(shí)現(xiàn)了隨機(jī)位置生成、圖像加載和拼圖繪制三個(gè)步驟。

async function init() {
  // 顯示加載指示器
  showLoading()
  targetX = Math.floor(Math.random() * (imgWidth - bolckSize - 60)) + 30;
  targetY = Math.floor(Math.random() * (imgHeight - bolckSize - 20)) + 10;
  var img = await loadImg(imgUrl+'?'+Math.random());
  // 創(chuàng)建背景畫布并繪制帶缺口的圖像
  var backCanvas = document.createElement('canvas')
  backCanvas.width = imgWidth;
  backCanvas.height = imgHeight;
  var backCtx = backCanvas.getContext('2d');
  backCtx.drawImage(img, 0, 0, 380, 190, 0, 0, imgWidth, imgHeight);
  backCtx.fillStyle = '#FFFFFF';
  backCtx.fillRect(targetX, targetY, 50, 50);
  backImg.src = backCanvas.toDataURL('image/png');
  // 創(chuàng)建拼圖塊
  var canvas = document.createElement('canvas')
  canvas.width = 50;
  canvas.height = 50;
  var ctx = canvas.getContext('2d');
  ctx.drawImage(img, targetX, targetY, bolckSize, bolckSize, 0, 0, bolckSize, bolckSize)
  blockImg.src = canvas.toDataURL('image/png');
  subBlock.style.top = (-201 + targetY) + 'px';
  // 隱藏加載指示器
  hideLoading()
}

2.2 拖拽交互處理

通過鼠標(biāo)事件監(jiān)聽實(shí)現(xiàn)流暢的拖拽體驗(yàn),當(dāng)用戶在滑塊上按下鼠標(biāo)并移動(dòng)時(shí),滑塊滑塊會(huì)隨鼠標(biāo)移動(dòng);當(dāng)用戶釋放鼠標(biāo)時(shí),進(jìn)行位置校驗(yàn),如果失敗滑塊會(huì)變?yōu)榧t色并平滑的回到起點(diǎn)位置。

// 鼠標(biāo)按下事件 - 開始拖拽
moveBlock.addEventListener('mousedown', function(e) {
  isDragging = true;
  startX = e.clientX;
  moveBlock.style.backgroundColor = '#337AB7';
  moveBlock.style.color = '#FFFFFF';
  verifyLeftBar.style.border = '1px solid #337AB7';
});
// 鼠標(biāo)移動(dòng)事件 - 拖拽過程
document.addEventListener('mousemove', function(e) {
  if (!isDragging) return;
  var newLeft = e.clientX - startX - 2;
  // 限制滑塊移動(dòng)范圍
  if (newLeft < 0) newLeft = 0;
  if (newLeft > maxWidth) newLeft = maxWidth;

  moveBlock.style.left = newLeft + 'px';
  verifyLeftBar.style.width = newLeft + 'px';
  verifyLeftBar.style.border = '1px solid #337AB7';
});
// 鼠標(biāo)釋放事件 - 結(jié)束拖拽
document.addEventListener('mouseup', function() {
  if (!isDragging) return;
  isDragging = false;
  var currentPosition = moveBlock.offsetLeft;
  if (Math.abs(currentPosition - targetX) <= tolerance) {
    moveBlock.style.backgroundColor = '#5CB85C';
    moveBlock.style.color = '#FFFFFF';
    verifyLeftBar.style.border = '1px solid #5CB85C';

    // 顯示成功提示
    verifyResult.textContent = '驗(yàn)證成功!';
    verifyResult.className = 'verify-result success';
    return;
  }
  moveBlock.style.backgroundColor = '#D9534F';
  moveBlock.style.color = '#FFFFFF';
  verifyLeftBar.style.border = '1px solid #D9534F';
  verifyLeftBar.style.backgroundColor = '#fff0f0';
  // 顯示失敗提示
  verifyResult.textContent = '驗(yàn)證失敗,請(qǐng)重試';
  verifyResult.className = 'verify-result fail';
  // 滑塊回彈動(dòng)畫
  moveBlock.style.transition = 'left 0.8s';
  moveBlock.style.left = '0px';

  verifyLeftBar.style.transition = 'width 0.8s';
  verifyLeftBar.style.width = '0px';

  // 動(dòng)畫結(jié)束后清除過渡效果
  setTimeout(() => {
    init()
    moveBlock.style.transition = '';
    verifyLeftBar.style.transition = '';
    moveBlock.style.backgroundColor = '#FFFFFF';
    moveBlock.style.color = '#999';
    verifyLeftBar.style.backgroundColor = '#F0FFF0';
    // 清除驗(yàn)證結(jié)果提示
    verifyResult.className = 'verify-result';
  }, 800);
});

四、擴(kuò)展建議

  • 添加服務(wù)器端驗(yàn)證,防止客戶端偽造結(jié)果
  • 增加行為特征檢測(cè),識(shí)別自動(dòng)化工具攻擊
  • 添加個(gè)性化拼圖形狀設(shè)計(jì),豐富視覺表現(xiàn)
  • 增加重試次數(shù)限制機(jī)制,防止無限重試

五、完整代碼

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>滑動(dòng)驗(yàn)證碼</title>
  <style>
      * {
          margin: 0;
          padding: 0;
          box-sizing: border-box;
      }
      body {
          background: #f5f5f5;
      }
      .container {
          display: flex;
          padding: 20px;
          justify-content: center;
      }
      .verify-container {
          background: #fff;
          width:400px;
          padding: 10px;
          border: 1px solid #ddd;
          user-select: none;
      }
      .verify-img {
          width: 380px;
          height: 190px;
          margin-bottom: 10px;
          position: relative;
      }
      .verify-bar-box {
          width: 380px;
          height: 50px;
          line-height: 50px;
          position: relative;
          background: #FFFFFF;
          text-align: center;
          box-sizing: content-box;
          border: 1px solid #ddd;
          border-radius: 4px;
          color: #999;
      }
      .verify-left-bar {
          background: #f0fff0;
          position: absolute;
          top: 0;
          left: 0;
          height: 50px;
      }
      .verify-move-block {
          position: absolute;
          top: 0;
          left: 0;
          background: #fff;
          cursor: pointer;
          box-sizing: content-box;
          box-shadow: 0 0 2px #888888;
          border-radius: 1px;
          width: 50px;
          height: 50px;
      }
      .verify-sub-block {
          position: absolute;
          border: 1px solid #ddd;
          height: 50px;
          left: -2px;
          top: -201px;
      }

      .verify-result {
          margin-top: 10px;
          padding: 8px 12px;
          text-align: center;
          border-radius: 4px;
          font-weight: bold;
          display: none;
      }

      .verify-result.success {
          background-color: #dff0d8;
          color: #3c763d;
          border: 1px solid #d6e9c6;
          display: block;
      }

      .verify-result.fail {
          background-color: #f2dede;
          color: #a94442;
          border: 1px solid #ebccd1;
          display: block;
      }
      .loading-indicator {
          padding: 5px 10px;
          border-radius: 4px;
      }
  </style>
</head>
<body>
<div class="container">
  <div class="verify-container">
    <div class="verify-box">
      <div class="verify-img">
        <img class="back-img" src="" style="width:100%;height:100%;"/>
        <div class="loading-indicator" id="backImgLoading" style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#666;font-size:14px;display:none;">加載中...</div>
      </div>
      <div class="verify-bar-box">
        <span class="verify-msg">向右滑動(dòng)完成驗(yàn)證</span>
        <div class="verify-left-bar"></div>
        <div class="verify-move-block">
          <span>></span>
          <div class="verify-sub-block">
            <img class="block-img" src="" style="width:100%;height:100%;"/>
          </div>
        </div>
      </div>
    </div>
    <div class="verify-result" id="verifyResult"></div>
  </div>
</div>
<script>
  var verifyBarBox = document.querySelector('.verify-bar-box');
  var moveBlock = document.querySelector('.verify-move-block');
  var verifyLeftBar = document.querySelector('.verify-left-bar');
  var backImg = document.querySelector('.back-img');
  var subBlock = document.querySelector('.verify-sub-block');
  var blockImg = document.querySelector('.block-img');
  var verifyResult = document.getElementById('verifyResult');
  var backImgLoading = document.getElementById('backImgLoading');

  var startX = 0;
  var isDragging = false;
  var maxWidth = verifyBarBox.offsetWidth - moveBlock.offsetWidth;

  var imgUrl = 'https://picsum.photos/380/190';
  var imgWidth = 380;
  var imgHeight = 190;
  var bolckSize = 50;
  var targetX = 0;
  var targetY = 0;
  var tolerance = 5;
  init();
  async function init() {
    // 顯示加載指示器
    showLoading()
    targetX = Math.floor(Math.random() * (imgWidth - bolckSize - 60)) + 30;
    targetY = Math.floor(Math.random() * (imgHeight - bolckSize - 20)) + 10;
    var img = await loadImg(imgUrl+'?'+Math.random());
    // 創(chuàng)建背景畫布并繪制帶缺口的圖像
    var backCanvas = document.createElement('canvas')
    backCanvas.width = imgWidth;
    backCanvas.height = imgHeight;
    var backCtx = backCanvas.getContext('2d');
    backCtx.drawImage(img, 0, 0, 380, 190, 0, 0, imgWidth, imgHeight);
    backCtx.fillStyle = '#FFFFFF';
    backCtx.fillRect(targetX, targetY, 50, 50);
    backImg.src = backCanvas.toDataURL('image/png');
    // 創(chuàng)建拼圖塊
    var canvas = document.createElement('canvas')
    canvas.width = 50;
    canvas.height = 50;
    var ctx = canvas.getContext('2d');
    ctx.drawImage(img, targetX, targetY, bolckSize, bolckSize, 0, 0, bolckSize, bolckSize)

    blockImg.src = canvas.toDataURL('image/png');
    subBlock.style.top = (-201 + targetY) + 'px';
    // 隱藏加載指示器
    hideLoading()
  }
  function showLoading() {
    backImgLoading.style.display = 'block';
    subBlock.style.display = 'none'
    backImg.style.display = 'none'
  }
  function hideLoading() {
    backImgLoading.style.display = 'none';
    subBlock.style.display = 'block'
    backImg.style.display = 'block'
  }

  // 繪制拼圖塊
  function loadImg(url){
    return new Promise((res,rej)=>{
      const im = new Image();
      im.crossOrigin='anonymous';
      im.onload = ()=>res(im);
      im.onerror= rej;
      im.src = url;
    });
  }

  // 鼠標(biāo)按下事件 - 開始拖拽
  moveBlock.addEventListener('mousedown', function(e) {
    isDragging = true;
    startX = e.clientX;
    moveBlock.style.backgroundColor = '#337AB7';
    moveBlock.style.color = '#FFFFFF';
    verifyLeftBar.style.border = '1px solid #337AB7';
  });
  // 鼠標(biāo)移動(dòng)事件 - 拖拽過程
  document.addEventListener('mousemove', function(e) {
    if (!isDragging) return;
    var newLeft = e.clientX - startX - 2;
    // 限制滑塊移動(dòng)范圍
    if (newLeft < 0) newLeft = 0;
    if (newLeft > maxWidth) newLeft = maxWidth;

    moveBlock.style.left = newLeft + 'px';
    verifyLeftBar.style.width = newLeft + 'px';
    verifyLeftBar.style.border = '1px solid #337AB7';
  });
  // 鼠標(biāo)釋放事件 - 結(jié)束拖拽
  document.addEventListener('mouseup', function() {
    if (!isDragging) return;
    isDragging = false;
    var currentPosition = moveBlock.offsetLeft;
    if (Math.abs(currentPosition - targetX) <= tolerance) {
      moveBlock.style.backgroundColor = '#5CB85C';
      moveBlock.style.color = '#FFFFFF';
      verifyLeftBar.style.border = '1px solid #5CB85C';

      // 顯示成功提示
      verifyResult.textContent = '驗(yàn)證成功!';
      verifyResult.className = 'verify-result success';
      return;
    }
    moveBlock.style.backgroundColor = '#D9534F';
    moveBlock.style.color = '#FFFFFF';
    verifyLeftBar.style.border = '1px solid #D9534F';
    verifyLeftBar.style.backgroundColor = '#fff0f0';
    // 顯示失敗提示
    verifyResult.textContent = '驗(yàn)證失敗,請(qǐng)重試';
    verifyResult.className = 'verify-result fail';
    // 滑塊回彈動(dòng)畫
    moveBlock.style.transition = 'left 0.8s';
    moveBlock.style.left = '0px';

    verifyLeftBar.style.transition = 'width 0.8s';
    verifyLeftBar.style.width = '0px';

    // 動(dòng)畫結(jié)束后清除過渡效果
    setTimeout(() => {
      init()
      moveBlock.style.transition = '';
      verifyLeftBar.style.transition = '';
      moveBlock.style.backgroundColor = '#FFFFFF';
      moveBlock.style.color = '#999';
      verifyLeftBar.style.backgroundColor = '#F0FFF0';
      // 清除驗(yàn)證結(jié)果提示
      verifyResult.className = 'verify-result';
    }, 800);
  });
</script>
</body>
</html>

總結(jié) 

到此這篇關(guān)于如何使用HTML+JavaScript實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼的文章就介紹到這了,更多相關(guān)HTML+JS滑動(dòng)驗(yàn)證碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

玉门市| 威信县| 奉化市| 江孜县| 阿城市| 浮山县| 武强县| 海南省| 嫩江县| 葵青区| 新密市| 搜索| 迭部县| 南漳县| 黑河市| 长兴县| 衡阳县| 三门县| 台北市| 安龙县| 桦南县| 金昌市| 远安县| 南投市| 井陉县| 穆棱市| 大丰市| 江西省| 贵溪市| 信阳市| 上饶县| 南靖县| 阳信县| 平乐县| 沙洋县| 靖宇县| 措美县| 射洪县| 修文县| 苏尼特左旗| 卢氏县|