当前位置: 首页 > news >正文

记录--前端实现登录拼图验证

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

前言

不知各位朋友现在在web端进行登录的时候有没有注意一个变化,以前登录的时候是直接账号密码通过就可以直接登录,再后来图形验证码,数字结果运算验证,到现在的拼图验证。这一系列的转变都是为了防止机器操作,但对于我们来说,有亿点麻烦,但也没办法呀。

今天我们也一起来做一个制造亿点麻烦的人,实现一个拼图验证。

实现原理

这个实现原理并不复杂,我们只需要一张图作为我们的拼接素材,我们再单独弄一个盒子,然后移动它,到我们的指定位置,到达指定范围内即验证通过,反之验证未通过。

既然原理我们知道了,那我们就开干吧。

实现前端登录拼图验证

本篇文章以 css 为主, javascript为辅实现。

搭建框架

我们要实现这个功能,我们需要先搭建出来一个框架。

// css<style>.check{width: 400px;height: 300px;background-repeat: no-repeat;background-size: 100% 100%;background-image: url(https://img0.baidu.com/it/u=2028084904,3939052004&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500);}
</style>// html<div class="check"></div>

我们画出来后,它就长下面图这样。

添加被校验区域及校验区域

我们需要添加一个被校验的区域及校验区域,用来做我们的校验,像下图这两个东西。

这里我们使用伪类来实现这两个区域。

校验区域

    .check::before{content: '';width: 50px;height: 50px;background: rgba(0, 0, 0, 0.5);border: 1px solid #fff;position: absolute;top: 100px;left: 280px;}

这样一个校验区域就做好了。

被校验区域

这里我们需要使用到background-position根据我们的校验区域大小进行切出我们的被校验区域。

background-imagebackground-repeat我们直接继承,background-position设置为校验区域的坐标位置(也就是距离topleft的距离),我们将background-size图片大小设为原盒子的大小。这样我们就得到了校验区域的那一片区域,也就是我们的被校验区域了。

    .check-child{content: '';width: 50px;height: 50px;border: 1px solid #fff;background-image: inherit;background-repeat: inherit;background-size: 400px 300px;background-position: -280px -100px;position: absolute;top: 100px;left: 10px;}// html<!-- 被校验区域 --><div class="check-child"></div>

添加拖动条

这里我们两个区域都添加完了,我们需要添加一个拖动条。

我们先添加一个拖动区域。

    // css.drag{width: 400px;height: 50px;background-color: #e3e3e3;margin-top: 10px;position: relative;}// html<div class="drag"></div>

现在拖动区域有了,我们需要在拖动区域内添加一个可拖动的盒子,及操作说明,不然看起来交互效果不友好。

添加可拖动的盒子及交互说明

我们添加一个可以拖动的盒子。

    // css.drag-child{width: 50px;height: 50px;background-color: aquamarine;z-index: 10;position: absolute;top: 0;left: 0;}// html<!-- 可拖动的盒子 --><div class="drag-child"></div>

 为了我们友好的交互,我们在拖动区域内给他添加操作说明。

    // css.drag-tips{display: flex;align-items: center;justify-content: end;width: 95%;height: 100%;margin: 0 auto;font-size: 12px;color: #8a8a8a;}// html<!-- 可拖动的盒子 --><div class="drag-tips"><span>按住左边按钮向右拖动完成上方图像验证</span></div>

拖动条动起来

这一步我们需要让我们的拖动盒子动起来,让他可以在拖动区域内随意的左右拖动。

    // 获取元素实例const drag = document.querySelector('.drag-child')// 声明鼠标按下事件const dragMouseDown = event => {// 添加鼠标移动事件document.addEventListener('mousemove', dragMouseMove)}// 监听鼠标移动事件const dragMouseMove = event => {// 获取当前 x 轴坐标const { offsetX } = eventif(offsetX < 0 || offsetX > 350){return}// 修改可移动盒子的 x 轴坐标drag.style.transform = `translateX(${offsetX}px)`}// 结束鼠标监听事件const dragMouseUP = event => {// 移除鼠标移动事件document.removeEventListener('mousemove', dragMouseMove)}// 添加鼠标按下事件document.addEventListener('mousedown', dragMouseDown)// 添加鼠标弹起事件document.addEventListener('mouseup', dragMouseUP)

现在我们的盒子就可以正常的拖动了,但现在它还有几个问题,我们后面来解决。

  1. 提示文字会被选中;
  2. 拖动区域内拖动会闪烁;

联动被校验区域

我们先让被校验区域跟着我们的拖动动起来。

    // 图形校验const check = document.querySelector('.check-child')// 修改被校验区域坐标check.style.left = `${offsetX}px`

这样我们的被校验区域就能够跟着动了,我们声明一个方法用来表示,通过校验的回调。

    // 通过校验回调const success = () => {console.log('通过校验');}// 监听鼠标移动事件const dragMouseMove = event => {// 获取当前 x 轴坐标const { offsetX } = eventif(offsetX < 0 || offsetX > 350){return}// 修改可移动盒子的 x 轴坐标drag.style.transform = `translateX(${offsetX}px)`// 修改被校验区域坐标check.style.transform = `translateX(${offsetX}px)`if(offsetX >= 278 && offsetX <= 285){// 执行回调success()}}

添加交互动画

这里我们在鼠标移出监听的时候添加一个动画,当当前未通过校验的时候我们给他还原到初始位置。

@keyframes move {to {transform: translateX(0);}
}
    // 结束鼠标监听事件const dragMouseUP = event => {// 移除鼠标移动事件document.removeEventListener('mousemove', dragMouseMove)// 获取当前 x 轴坐标const { offsetX } = eventif(offsetX < 278 || offsetX > 285){// 修改可移动盒子的 x 轴坐标drag.style.animation = 'move 0.5s ease-in-out'// 修改被校验区域坐标check.style.animation = 'move 0.5s ease-in-out'// 动画结束监听回调const animationEnd = ()=>{// 修改可移动盒子的 x 轴坐标drag.style.transform = `translateX(${0}px)`// 修改被校验区域坐标check.style.transform = `translateX(${0}px)`// 清除动画属性drag.style.animation = ''check.style.animation = ''// 移出动画结束监听document.removeEventListener("animationend", animationEnd)}// 添加动画结束监听document.addEventListener("animationend", animationEnd)}}

当我们未通过校验,且放开鼠标的时候,它就会自动回到初始位置。

解决遗留问题

1、 提示文字会被选中

我们在提示文字的样式中添加user-select: none;,禁用掉文字选择。

    /* 提示文字说明 */.drag-tips{display: flex;align-items: center;justify-content: end;width: 95%;height: 100%;margin: 0 auto;font-size: 12px;color: #8a8a8a;user-select: none;z-index: 1;position: absolute;top: 0;left: 0;}

2、 在拖动区域内拖动会闪烁

我们将我们刚刚使用的offsetX改为pageX。这里需要注意一下边距偏移量的问题哦。

    // 监听鼠标移动事件const dragMouseMove = event => {console.log(event);// 获取当前 x 轴坐标const { pageX }  = eventif(pageX < 0 || pageX > 350){return}// 修改可移动盒子的 x 轴坐标drag.style.transform = `translateX(${pageX}px)`// 修改被校验区域坐标check.style.transform = `translateX(${pageX}px)`if(pageX >= 278 && pageX <= 285){// 执行回调success()}}// 结束鼠标监听事件const dragMouseUP = event => {// 移除鼠标移动事件document.removeEventListener('mousemove', dragMouseMove)// 获取当前 x 轴坐标const { pageX } = eventif(pageX < 278 || pageX > 285){// 修改可移动盒子的 x 轴坐标drag.style.animation = 'move 0.5s ease-in-out'// 修改被校验区域坐标check.style.animation = 'move 0.5s ease-in-out'// 动画结束监听回调const animationEnd = ()=>{// 修改可移动盒子的 x 轴坐标drag.style.transform = `translateX(${0}px)`// 修改被校验区域坐标check.style.transform = `translateX(${0}px)`// 清除动画属性drag.style.animation = ''check.style.animation = ''// 移出动画结束监听document.removeEventListener("animationend", animationEnd)}// 添加动画结束监听document.addEventListener("animationend", animationEnd)}}

效果图

我们看一下效果图。

完整代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>drag</title><style>*{margin: 0;padding: 0;}body{padding: 20px;}/* 图形拼图验证码 */.check{width: 400px;height: 300px;background-repeat: no-repeat;background-size: 100% 100%;background-image: url(https://img0.baidu.com/it/u=2028084904,3939052004&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500);position: relative;}.check::before{content: '';width: 50px;height: 50px;background: rgba(0, 0, 0, 0.5);border: 1px solid #fff;position: absolute;top: 100px;left: 280px;}.check-child{content: '';width: 50px;height: 50px;border: 1px solid #fff;background-image: inherit;background-repeat: inherit;background-size: 400px 300px;background-position: -280px -100px;position: absolute;top: 100px;left: 0;}/* 拖动条 */.drag{width: 400px;height: 50px;background-color: #e3e3e3;margin-top: 10px;position: relative;}/* 可拖动的盒子 */.drag-child{width: 50px;height: 50px;background-color: aquamarine;z-index: 10;position: absolute;top: 0;left: 0;}/* 提示文字说明 */.drag-tips{display: flex;align-items: center;justify-content: end;width: 95%;height: 100%;margin: 0 auto;font-size: 12px;color: #8a8a8a;user-select: none;z-index: 1;position: absolute;top: 0;left: 0;}@keyframes move {to {transform: translateX(0);}}</style>
</head>
<body><!-- 图形校验区域 --><div class="check"><!-- 被校验区域 --><div class="check-child"></div></div><!-- 拖动条 --><div class="drag"><!-- 操作说明 --><div class="drag-tips"><span>按住左边按钮向右拖动完成上方图像验证</span></div><!-- 可拖动的盒子 --><div class="drag-child"></div></div>
</body>
<script>// 获取元素实例const drag = document.querySelector('.drag-child')// 图形被校验区域const check = document.querySelector('.check-child')// 通过校验回调const success = () => {console.log('通过校验');}// 声明鼠标按下事件const dragMouseDown = event => {// 添加鼠标移动事件document.addEventListener('mousemove', dragMouseMove)}// 监听鼠标移动事件const dragMouseMove = event => {// 获取当前 x 轴坐标const { pageX }  = eventif(pageX < 0 || pageX > 350){return}// 修改可移动盒子的 x 轴坐标drag.style.transform = `translateX(${pageX}px)`// 修改被校验区域坐标check.style.transform = `translateX(${pageX}px)`if(pageX >= 278 && pageX <= 285){// 执行回调success()}}// 结束鼠标监听事件const dragMouseUP = event => {// 移除鼠标移动事件document.removeEventListener('mousemove', dragMouseMove)// 获取当前 x 轴坐标const { pageX } = eventif(pageX < 278 || pageX > 285){// 修改可移动盒子的 x 轴坐标drag.style.animation = 'move 0.5s ease-in-out'// 修改被校验区域坐标check.style.animation = 'move 0.5s ease-in-out'// 动画结束监听回调const animationEnd = ()=>{// 修改可移动盒子的 x 轴坐标drag.style.transform = `translateX(${0}px)`// 修改被校验区域坐标check.style.transform = `translateX(${0}px)`// 清除动画属性drag.style.animation = ''check.style.animation = ''// 移出动画结束监听document.removeEventListener("animationend", animationEnd)}// 添加动画结束监听document.addEventListener("animationend", animationEnd)}}// 添加鼠标按下事件document.addEventListener('mousedown', dragMouseDown)// 添加鼠标弹起事件document.addEventListener('mouseup', dragMouseUP)</script>
</html>

本文转载于:

https://juejin.cn/post/7175818459379417146

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

相关文章:

记录--前端实现登录拼图验证

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 前言 不知各位朋友现在在web端进行登录的时候有没有注意一个变化&#xff0c;以前登录的时候是直接账号密码通过就可以直接登录&#xff0c;再后来图形验证码&#xff0c;数字结果运算验证&#xff0c…...

【Go语言基础】Go语言中的map集合详细使用(附带源码)

文章目录Go语言中的map集合1-1 定义1-2 map遍历1-3 map集合删除1-4 map是引用类型Go语言中的map集合 Go 语言提供了内置类型 map集合&#xff0c;它将一个值与一个键关联起来&#xff0c;可以使用相应的键检索值。 map是一种集合&#xff0c;可以像遍历数组或切片那样去遍历它…...

C++11 lambda

Lambda 介绍 Lambda 函数也叫匿名函数&#xff0c; 是C 11中新增的特性; 1. Lambda函数的好处 如果你的代码里面存在大量的小函数&#xff0c;而这些函数一般只被调用一次&#xff0c;那么将他们重构成 lambda 表达式。 Lambda函数使代码变得更加紧凑、更加结构化和更富有表现…...

【新】华为OD机试 - 分苹果(Python)

分苹果 题目 AB两个人把苹果分为两堆 A希望按照他的计算规则等分苹果 他的计算规则是按照二级制加法计算 并且不计算进位12+5=9(1100+0101=9), B的计算规则是十进制加法, 包括正常进位,B希望在满足A的情况下获取苹果重量最多 输入苹果的数量和每个苹果重量 输出满足A的情况下…...

Python 模块

Python 模块(Module)&#xff0c;是一个 Python 文件&#xff0c;以 .py 结尾&#xff0c;包含了 Python 对象定义和Python语句。 模块让你能够有逻辑地组织你的 Python 代码段。 把相关的代码分配到一个模块里能让你的代码更好用&#xff0c;更易懂。 模块能定义函数&#…...

gdb调试功能从零到会(Linux详解)

目录 &#x1f440; 1.安装gdb &#x1f440;2.判断是否安装成功 &#x1f440;3.改成debug方式发布。 &#x1f440; 4.gdb功能简介 前言 gdb是Linux 下功能全面的调试工具。gdb支持断点、单步执行、打印变量、观察变量、查看寄存器、查看堆栈等调试手段。在Linux环境软件…...

【C语言学习笔记】:数组、指针相关面试题

无特殊说明情况下&#xff0c;下面所有题s目都是linux下的32位C程序。 「1、计算以下sizeof的值。」 char str1[] {a, b, c, d, e}; char str2[] "abcde";char *ptr "abcde";char book[][80]{"计算机应用基础","C语言","C程…...

go语言环境配置 项目启动

一 安装go语言 go语言各个版本之间兼容性比较差。所以可能你需要安装固定的版本 1 安装最新版的go brew install go2 查看go可以安装的版本 brew search go3 安装指定版本的go brew install go1.134 查看安装的go语言的版本 go version5 查看go的安装路径 which go || w…...

Springboot 使用插件 自动生成Mock单元测试 Squaretest

缘起 很多公司对分支单测覆盖率会有一定的要求&#xff0c;比如 单测覆盖率要达到 60% 或者 80%才可以发布。 有时候工期相对紧张&#xff0c;就优先开发功能&#xff0c;测试功能&#xff0c;然后再去补单元测试。 但是编写单元测试又比较浪费时间&#xff0c;有没有能够很大…...

「JVM 执行引擎」栈架构的字节码的解释执行引擎

JVM 执行引擎在执行 Java 代码时有解释执行&#xff08;通过解释器执行&#xff09;和编译执行&#xff08;通过即时编译器产生本地代码执行&#xff09;两种选择&#xff1b; HotSpot 实际的实现中&#xff0c;模版解释器工作时&#xff0c;并不是按照概念模型中进行机械式计…...

SSM项目-商城后台管理系统

SSM项目-商城后台管理系统开发说明开发环境项目界面演示项目功能具体的技术指标开发过程1、搭建SSM框架1.1、建库建表1.2、新建Maven工程1.3、配置pom.xml1.4、目录结构1.5、jdbc.properties1.6、mybatis-config.xml1.7 两个Spring的配置文件applicationContext_dao.xmlapplica…...

什么是装运单IFTMIN?

符合EDIFACT国际报文标准的IFTMIN主要用于传输电子运输订单&#xff0c;这些装运单作为EDI数据交换的一部分&#xff0c;由客户或托运人发送给物流服务提供商。通过EDI传输的运输信息可以被用来计划当前所需的运输能力&#xff0c;并且物流服务提供商也可以据此提前将包装材料准…...

深度负反馈

负反馈放大电路的方块图因为负反馈放大电路有四种组态&#xff0c;而且对于同一种组态&#xff0c;具体电路也各不相同&#xff1b;所以为了研究负反馈放大电路的共同规律&#xff0c;可以利用方块图来描述所有电路一.负反馈放大电路的方块图表示法任何负反馈放大电路都可以用下…...

【每日随笔】手指训练 ( 产品需求探索、技术无关 | 手指训练作用 | 哪些人需要手指训练 | 手指操 | 手指康复训练器材 )

文章目录一、手指训练作用二、哪些人需要手指训练三、手指操四、手指康复训练器材产品需求探索 , 研究下手指训练的市场 , 前景 , 是否可以开发 ; 一、手指训练作用 手指训练作用 : 改善 上肢协调性手眼 协调性训练提高 手指 抓握 能力提高 手指 灵活性提高 上肢运动 准确性 和…...

Apple Safari 16.3 - macOS 专属免费浏览器 (独立安装包免费下载)

Safari 浏览器 16 for macOS Montery, Big Sur 请访问原文链接&#xff1a;https://sysin.org/blog/apple-safari-16/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;www.sysin.org 之前 Safari 浏览器伴随 macOS 更新一起发布&#xff…...

【java】Spring Boot --Spring Boot 集成 MyBatis

文章目录1. 前言2. 实例场景3. 数据库模块实现4. Spring Boot 后端实现4.1 使用 Spring Initializr 创建项目4.2 引入项目依赖4.3 数据源配置4.4 开发数据对象类4.5 开发数据访问层4.6 添加 MyBatis 映射文件5. 测试6. 小结1. 前言 企业级应用数据持久层框架&#xff0c;最常见…...

python正则表达式

python正则表达式 作者&#xff1a;AOAIYI 创作不易&#xff0c;如果觉得文章不错或能帮到你学习&#xff0c;记得点赞收藏评论一下哦 文章目录python正则表达式一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤总结一、实验目的 学会使用常见的正则表达式 二、…...

【C++】二叉树的非递归遍历

非递归遍历二叉树一、二叉树的前序遍历二、二叉树的中序遍历三、二叉树的后序遍历3.1 方法一3.2 方法二一、二叉树的前序遍历 题目链接 我们可以把任何一棵树看成左路节点&#xff0c;左路节点和右子树。先访问左路节点&#xff0c;再访问左路节点的右子树。在右子树中也重复这…...

Linux——线程同步(条件变量、POSIX信号量)和线程池

一.线程同步&#xff08;一&#xff09;.概念线程同步是一种多线程关系&#xff0c;指的是线程之间按照特定顺序访问临界资源&#xff0c;进而能够避免线程饥饿问题。所谓线程饥饿指的是某个线程长期“霸占”临界资源&#xff0c;导致其他线程无法访问该资源。而通过线程同步机…...

leaflet 上传CSV文件,导出geojson格式文件(064)

第064个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中加载CSV文件,将图形显示在地图上。点击导出geojson,下载成geojson文件。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共114行)安装插件…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

macOS 终端智能代理检测

&#x1f9e0; 终端智能代理检测&#xff1a;自动判断是否需要设置代理访问 GitHub 在开发中&#xff0c;使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新&#xff0c;例如&#xff1a; fatal: unable to access https://github.com/ohmyzsh/oh…...

Vue 3 + WebSocket 实战:公司通知实时推送功能详解

&#x1f4e2; Vue 3 WebSocket 实战&#xff1a;公司通知实时推送功能详解 &#x1f4cc; 收藏 点赞 关注&#xff0c;项目中要用到推送功能时就不怕找不到了&#xff01; 实时通知是企业系统中常见的功能&#xff0c;比如&#xff1a;管理员发布通知后&#xff0c;所有用户…...

机器学习的数学基础:线性模型

线性模型 线性模型的基本形式为&#xff1a; f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法&#xff0c;得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...