jquery实现文字点选验证码

git地址: 点击获取源码

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

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

二. 效果图:

jquery实现文字点选验证码_文字点选

三、代码:

  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.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  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.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  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.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  1. 词库文件:data.json
{
  "data": [
    "快乐的大脚",
    "阖家快乐",
    "祝福您",
    "萌新的快乐",
    "彩色溜",
    "恭喜发财祝您",
    "假期愉快",
    "天天开心呀",
    "今天是好天气",
    "美丽的神话",
    "加菲猫",
    "小马宝利",
    "记得加油呀",
    "巴啦啦小魔仙",
    "大头儿子",
    "疯狂动物城"
  ]
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.