jquery实现文字点选验证码

git地址:点击获取源码

一、功能说明(文字点选验证码)

  1. 词组库内存在大量3~6字随机词组,
  2. 从词组库内随机找出一组词组,随机展现在显示区
  3. 点击按钮,弹出验证码区域
  4. 将词组内的随机数量文字随机顺序作为验证文本进行校验
  5. 点击文字添加标记并计数,当点击次数与验证文本数量一致,自动校验
  6. 验证通过后,提示成功,关闭验证区域
  7. 验证失败,提示失败,刷新验证码
  8. 点击显示区内刷新按钮,刷新验证码

二. 效果图:

rsss7-zyxos-1.gif

三、代码:

  1. 验证区htmlindex.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 引入验证区样式 -->
  <link rel="stylesheet" type="text/css" href="css/index.css" />
  <style>
    .my-container {
      position: relative;
      top: 20px;
      left: 50px;
    }
  </style>
</head>

<body>
  <div class="my-container">
    <input type="text"><button id="btn">点击触发验证码</button>
  </div>
  <!-- 验证码区域 -->
  <div id="verification">
    <!-- 刷新 -->
    <div class="refresh"></div>
    <!-- 验证结果 -->
    <div id="resultBox"></div>
    <!-- 验证词组显示区 -->
    <div id="box"></div>
  </div>

  <script src="js/jquery-1.9.1.min.js"></script>
  <!-- 引入验证区js -->
  <script src="js/index.js" type="text/javascript" charset="utf-8"></script>
  <script>
    /**
     * 点击按钮显示验证区,初始化验证区
     */
    $('#btn').click(() => {
      $('#verification').show()
      init();
    })
  </script>

</body>

</html>
  1. 验证区js:index.js
// TODO获取词库
$(function () {
  fetch("/js/data.json")
    .then((response) => response.json()) // 解析JSON响应
    .then((response) => {
      textData = response.data;
    })
    .catch((error) => console.error("Error:", error));
});

/**
 * @constant box 容器
 * @variate place 文字分散在容器中的随机位置
 * @variate textData 文字库集合
 * @variate verifyWord 需要校验的词组,用于渲染布局
 * @constant minVerifyWordLen 随机文字最小数量
 * @variate verifyText 需要校验的随机文字,用于展示
 * @variate verifyTextIdxs 需要校验的文本,取verifyText的index值
 * @variate verifyClickCount 点击校验文字的次数,达到verifyTextIdxs长度进行校验
 * @variate selectedIdxs 选中文字的index集合
 */

const box = $("#box");
let place = [
  { left: "0px", top: "0px" },
  { left: "120px", top: "0px" },
  { left: "240px", top: "0px" },
  { left: "0px", top: "90px" },
  { left: "120px", top: "90px" },
  { left: "240px", top: "90px" },
];

let textData = [];
let verifyWord = "";
const minVerifyWordLen = 3;
let verifyText = "";
let verifyTextIdxs = [];
let verifyClickCount = 0;
let selectedIdxs = [];

/**
 * @function getVerifyWord 获取随机校验词组
 */

function getVerifyWord() {
  return textData[Math.floor(Math.random() * (textData.length - 1))];
}

/**
 * @function getVerifyText 获取随机校验文字
 */
function getVerifyText() {
  // 随机选取校验文字数量
  let lenRandom = Math.ceil(Math.random() * verifyWord.length);
  if (lenRandom < minVerifyWordLen) {
    lenRandom = minVerifyWordLen;
  }

  const verifyArray = verifyWord.split("");
  const result = [];

  // 获取随机需要校验的文字
  for (let i = 0; i < lenRandom; i++) {
    let index = Math.floor(Math.random() * verifyArray.length);
    result.push(verifyArray[index]);
    verifyArray.splice(index, 1); // 移除已选的元素以避免重复
  }

  return result.join("");
}

/**
 * @function getVerifyText 获取校验文字的idx
 */
function getVerifyTextIdxs() {
  const wordArray = verifyWord.split("");
  const textArray = verifyText.split("");
  const result = [];

  for (let text of textArray) {
    const idx = wordArray.findIndex((word) => word === text);
    result.push(idx);
  }

  return result;
}

/**
 * @function clear 重置
 */
function clear() {
  box.empty();
  verifyWord = getVerifyWord();
  verifyText = getVerifyText();
  verifyTextIdxs = getVerifyTextIdxs();
  verifyClickCount = 0;
  selectedIdxs = [];

  $("#resultBox").html(`请依次点击: <span>${verifyText}</span>`);

  place.sort(() => {
    return Math.random() - 0.5;
  });
}

/**
 * @function init 初始化
 */
function init() {
  // 重置内容
  clear();

  verifyWord.split("").map((text, idx) => {
    createVerifyBox(text, idx);
  });

  /**
   * 创建存放每个校验文字的容器
   * @param {string} text 文字
   * @param {number} idx 索引
   * @attribute {number} index 文字标签的index值
   * @attribute {string: true | false } judge 判断标签是否被点击
   */
  function createVerifyBox(text, idx) {
    //创建box分割的div容器
    let divEl = $('<div class="item"></div>');
    divEl.css({
      left: place[idx].left,
      top: place[idx].top,
    });

    //创建span标签存储校验文字
    let spanEl = $(`<span class="spanEl">${text}</span>`);
    divEl.append(spanEl);
    box.append(divEl);

    addSpanElCss(divEl, spanEl);

    // 添加属性,
    // 用于存入selectedIdxs
    spanEl.data("index", idx);
    spanEl.data("judge", "true");
  }

  /**
   * 添加span项样式
   */
  function addSpanElCss(divEl, spanEl) {
    const lt = divEl.width() - spanEl.width() - 10;
    const rt = divEl.height() - spanEl.height() - 10;
    let left = Math.floor(Math.random() * lt);
    let top = Math.floor(Math.random() * rt);
    spanEl.css({
      left: left + "px",
      top: top + "px",
    });
  }

  //span点击事件
  $("#box .item span").click(function (e) {
    if ($(this).data("judge") == "true") {
      selectedIdxs.push($(this).data("index"));
      console.log(selectedIdxs, "selectedIdxs", verifyTextIdxs);
      $(this).data("judge", "false");
      verifyClickCount++;
      appendRadio(e);
      // 验证
      if (verifyClickCount === verifyTextIdxs.length) {
        getVerifyResult();
      }
    }
  });

  //点击事件,生成圆点
  function appendRadio(e) {
    const radioEl = $(`<div class='radio'>${verifyClickCount}</div>`);
    box.append(radioEl);

    const wt = radioEl.width() / 2;
    const ht = radioEl.height() / 2;

    radioEl.css({
      left: e.pageX - box.offset().left - wt + "px",
      top: e.pageY - box.offset().top - ht + "px",
    });
  }
}

/**
 * @function getVerifyResult 获取校验结果
 */
function getVerifyResult() {
  if (selectedIdxs.join() == verifyTextIdxs.join()) {
    $("#resultBox span").html("验证成功");
    $("#resultBox span").css("color", "#1abd6c");
    setTimeout(() => {
      $("#verification").hide();
    }, 500);
    // TODO 验证成功后操作
  } else {
    $("#resultBox span").html("验证失败");
    $("#resultBox span").css("color", "red");
    setTimeout(() => {
      init();
    }, 500);
  }
  verifyClickCount = 0;
}

/**
 * @function 刷新
 */
$(".refresh").click(() => {
  init();
});

  1. 验证区css: index.css
#verification {
	position: absolute;
	top: 60px;
	left: 50px;
	display: none;
}

/* 刷新 */
#verification .refresh{
	position: absolute;
	top: 50px;
	right: 10px;
	z-index: 10;
	width: 28px;
	height: 28px;
	cursor: pointer;
	background-image: url("/img/refresh.png");
	background-size: 100% 100%;
}

#box{
	position: relative;
	width: 360px;
	height: 180px;
	padding: 0 20px;
	border-radius: 10px;
	background-image: url("/img/bg.png");
	background-repeat: no-repeat;
}

#box .item{
	position: absolute;
	width: 120px;
	height: 90px;
}

#box .radio{
	position: absolute;
	z-index: 10;
	width: 30px;
	height: 30px;
	line-height: 30px;
	text-align: center;
	border-radius: 50%;
	color: #fff;
	background-color: #1abd6c;
}

#box span{
	font-size: 40px;
	position: absolute;
	z-index: 4;
	color: #4463cb;
	font-weight: bold;
}

#box span:hover{
	cursor: pointer;
}

#resultBox{
	height: 40px;
	font-size: 18px;
	line-height: 40px;
}

#resultBox span{
	font-size: 22px;
	font-weight: bold;
	color: #1f1f1f;
}

  1. 词库文件:data.json
{
  "data": [
    "快乐的大脚",
    "阖家快乐",
    "祝福您",
    "萌新的快乐",
    "彩色溜",
    "恭喜发财祝您",
    "假期愉快",
    "天天开心呀",
    "今天是好天气",
    "美丽的神话",
    "加菲猫",
    "小马宝利",
    "记得加油呀",
    "巴啦啦小魔仙",
    "大头儿子",
    "疯狂动物城"
  ]
}