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

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

前言

不知各位朋友现在在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 } = event
        if(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 } = event
        if(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 } = event

        if(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 }  = event
        if(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 } = event

        if(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 }  = event
        if(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 } = event

        if(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

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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
拼图 Pintuer更新说明: 【起步】 调整框架文件,页面模版 进一步补充及丰富颜色配置方法 增加了改为直角的方法 去除了IE6-8下的js控制响应,改为responed.js实现媒体查询。【CSS】 改变了标题文本的大小,更适合中文文本 增加文本行距样式 增加背加反色:反色的文字都为白色。 增加了边框、圆角样式 新增填充、边界样式大小 新增CSS动画效果 修改了图片的样式 重新定义了表单样式 表单增加了按钮式的单选及多选 按钮加上悬浮样式 增加了圆角和直角按钮 更新了引用的样式【元件】 新定义了网格间距(分别为默认的0px, small:4px, middle:10px, big:20px) css小图标让位于字体图标而改名 新增500多个Font Awesome字体图标 增加了导航样式 增加了小号的进度条效果。 调整了按钮组的.active颜色属性 标签式选中改为按钮式选中 修改了文字色块的样式 调整了所有表单组的样式 增加了部份输入框组样式 列表组增加了条纹效果【JS组件】 选项标签增加了更多样式 修改了警告框的样式 增加了表单单选多选效果 表单验证随表单组的样式改变而改变(验证方法未改变) 增加了轮播效果及响应办法 增加了置顶及置底功能 增加了滚动监听功能 增加了折叠效果【模块】 新增头部 新增导航条 新增主页 新增面包屑 新增列表 新增分页 新增内容 新增底部拼图 Pintuer:中国版的Bootstrap,是国内优秀的HTML、CSS、JS跨屏响应式开源前端框架,使用最新浏览器技术,为快速的前端开发提供一系统的文本、图标、媒体、表格、表单、按钮、菜单、网格系统等样式工具包,占用资源小,使用拼图可以快速构建简洁、优雅而且自动适应手机、平板、桌面电脑等设备的前端界面,让前端开发像玩游戏一下快乐而轻松。 拼图前端框架在传统CSS框架的基本上,增加了HTML5、CSS3、JS等技术组合应用,应用于最新的浏览器技术,同时兼容较早的浏览器,新旧结合,承前启后,开发者只需把框架文件引入到项目中,就可以初现快速的共同开发,改变以往建立PC网站同时,再建立手机网站的局面,实现一站响应所有设备,大大提高了开发效率。功能特色: 移动优先、跨屏响应:拼图以移动设备为基点,优先适应于移动设备;从移动设备扩大到平板、桌面电脑等设备,实现跨屏响应,兼容桌面浏览器的同时,更适应了移动互联网的潮流。 组件丰富、海量插件:拼图前端框架重新定义了CSS基础、常用元件及JS组件,可快速构架前端界面,实现跨屏响应。同时兼容所有jQuery插件,在项目中可以灵活使用,让前端开发如虎添翼。 轻量高效、国产开源:拼图基于应用广泛jQuery插件,轻量高效;相对于国外的前端框架,拼图前端框架侧重于对中文的支持,符合国人的视觉及体验,实现到国内主流浏览器的支持,减少兼容性测试时间,提高开发效率。
WPF 登录验证方式中,滑动拼图是一种常见的实现方式,通常被用于防止机器人或者恶意攻击。 实现滑动拼图的基本思路如下: 1. 在登录页面上添加一个滑块组件,包含一个滑块和一个拼图区域。 2. 当用户登录时,需要先通过输入用户名和密码进行身份验证验证通过后,显示滑块组件。 3. 用户需要按住滑块,将其拖动到正确的位置,使得拼图区域中的图片与滑块上的图片完全重合。 4. 当滑块被拖动到正确的位置时,将用户的登录信息提交给服务器进行验证。 下面是实现滑动拼图的示例代码: ```xml <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!-- 用户名和密码输入框 --> <StackPanel Grid.Row="0"> <TextBox Name="txtUsername" Margin="10" Width="200" PlaceholderText="Enter username"/> <PasswordBox Name="txtPassword" Margin="10" Width="200" PlaceholderText="Enter password"/> <Button Name="btnLogin" Content="Login" Click="btnLogin_Click" Margin="10"/> </StackPanel> <!-- 滑块组件 --> <Grid Grid.Row="1" Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <!-- 拼图区域 --> <Image Name="imgPuzzle" Stretch="Fill" Source="puzzle.jpg" Grid.Column="0"/> <!-- 滑块 --> <Canvas Name="canvasSlider" Width="100" Height="100" Grid.Column="1"> <Image Name="imgSlider" Stretch="Fill" Source="slider.jpg"/> </Canvas> </Grid> </Grid> ``` ```csharp private bool _isSliding; private Point _startPoint; private void canvasSlider_PointerPressed(object sender, PointerRoutedEventArgs e) { _isSliding = true; _startPoint = e.GetCurrentPoint(canvasSlider).Position; } private void canvasSlider_PointerMoved(object sender, PointerRoutedEventArgs e) { if (_isSliding) { Point currentPoint = e.GetCurrentPoint(canvasSlider).Position; double distance = currentPoint.X - _startPoint.X; if (distance >= 0 && distance <= imgPuzzle.ActualWidth - canvasSlider.ActualWidth) { Canvas.SetLeft(canvasSlider, distance); } } } private void canvasSlider_PointerReleased(object sender, PointerRoutedEventArgs e) { _isSliding = false; if (Canvas.GetLeft(canvasSlider) == imgPuzzle.ActualWidth - canvasSlider.ActualWidth) { // 验证通过,提交登录信息 string username = txtUsername.Text; string password = txtPassword.Password; // TODO: 提交登录信息 } else { // 验证失败,重置滑块位置 Canvas.SetLeft(canvasSlider, 0); } } ``` 在代码中,我们使用了 PointerPressed、PointerMoved 和 PointerReleased 事件来实现滑块的拖动,并在 PointerReleased 事件中进行验证。当滑块被拖动到正确的位置时,我们可以提交用户的登录信息给服务器进行验证。否则,重置滑块位置并提示用户验证失败。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值