滑动验证码-elementui实现

news2024/9/21 12:41:28

使用elementui框架实现

html代码
<div class="button-center">
    <el-popover
                placement="top"
                :width="imgWidth"
                title="安全验证"
                trigger="manual"
                v-model="popoverVisible"
                @hide="popoverHide"
                @show="popoverShow">
        <div class="z-popover">
            <!--    滑块图片        -->
            <canvas id="sliderImg"></canvas>
            <!--背景图片-->
            <canvas id="backgroundImg"></canvas>

            <el-slider v-model="sliderValue" :show-tooltip="showTooltip" @input="sliderInput"
                       @change="sliderChange" v-mousedown="sliderDown"></el-slider>
            <el-divider></el-divider>
            <i class="el-icon-circle-close z-el-popover-size" @click="popoverVisible = false"
               title="关闭"></i>
            <i class="el-icon-refresh z-el-popover-size" @click="popoverShow"
               title="更换验证码"></i>
            <span class="z-slider-result">{{sliderResult}}</span>
        </div>
        <el-button slot="reference" type="primary" @click="login()" :disabled="isDisabled"
                   class="login-register-button-width">登录
        </el-button>
    </el-popover>

</div>
主要代码:
function SliderImg(width, height, r, w) {
    this.width = width;
    this.height = height;
    this.r = r;
    this.w = w;

    // 使用双缓冲区去闪烁
    let getBufferCanvas = () => {
        // 创建隐藏Canvas
        let buffer = document.createElement('canvas');
        buffer.width = this.width;
        buffer.height = this.height;
        buffer.ctx = buffer.getContext('2d');
        buffer.ctx.setTransform(1, 0, 0, 1, 0, 0);
        return buffer;
    }

    let init = () => {
        if (!this.backgroundImg || !this.sliderImg) {
            this.backgroundImg = document.getElementById("backgroundImg")
            this.backgroundImg.width = this.width;
            this.backgroundImg.height = this.height;
            this.backgroundImg.ctx = this.backgroundImg.getContext('2d');
            this.sliderImg = document.getElementById("sliderImg")
            this.sliderImg.width = this.width;
            this.sliderImg.height = this.height;
            this.sliderImg.ctx = this.sliderImg.getContext('2d');
        }
        this.sliderWidth = 2 * (this.r + this.w);
        $("#sliderImg").css('position', 'absolute').css("left", "0px");
        this.buffer1 = this.buffer1 == null ? getBufferCanvas() : this.buffer1;
        this.buffer2 = this.buffer2 == null ? getBufferCanvas() : this.buffer2;
        this.pos = getPos();
    }

    this.drawImg = function (src) {
        init();
        let img = new Image();
        img.src = src;
        img.onload = () => {
            drawBgBlock(img, this.buffer1.ctx);
            drawSiBlock(img, this.buffer2.ctx);
        }
    }

    let drawBgBlock = (img, ctx) => {
        ctx.clearRect(0, 0, this.width, this.height);
        ctx.drawImage(img, 0, 0, this.width, this.height);
        // 绘制滑块的形状
        drawBlock(ctx);
        ctx.fill();
        // 将缓冲区内容绘制到实际的画布中
        this.backgroundImg.ctx.clearRect(0, 0, this.width, this.height);
        this.backgroundImg.ctx.drawImage(this.buffer1, 0, 0, this.width, this.height);
    }

    let drawSiBlock = (img, ctx) => {
        ctx.clearRect(0, 0, this.width, this.height);
        ctx.drawImage(img, 0, 0, this.width, this.height);
        // 创建一个临时画布画一个圆, 然后将图片绘制上去, 形成一个滑块
        let tempCanvas = getBufferCanvas();
        tempCanvas.ctx.translate(-this.pos.siOffset, 0);
        drawBlock(tempCanvas.ctx);
        tempCanvas.ctx.clip();
        tempCanvas.ctx.drawImage(this.buffer2, 0, 0);
        // 将缓冲区内容绘制到实际的画布中
        this.sliderImg.ctx.clearRect(0, 0, this.width, this.height);
        this.sliderImg.ctx.drawImage(tempCanvas, 0, 0, this.width, this.height);
    }

    /**
     * 绘制缺口
     *
     * @param ctx
     */
    let drawBlock = (ctx) => {
        let x = this.pos.x, y = this.pos.y, r = this.pos.r, w = this.pos.w;
        ctx.beginPath();
        ctx.moveTo(x, y);
        // left
        // ctx.lineTo(x, y + w); 第一条直线可以省略, 下同理
        ctx.arc(x, y + w + r, r, -0.5 * Math.PI, 0.5 * Math.PI, false);
        ctx.lineTo(x, y + 2 * (w + r));
        // bottom
        ctx.arc(x + w + r, y + 2 * (w + r), r, Math.PI, 0, true);
        ctx.lineTo(x + 2 * (w + r), y + 2 * (w + r));
        // right
        ctx.arc(x + 2 * (w + r), y + w + r, r, 0.5 * Math.PI, -0.5 * Math.PI, true);
        ctx.lineTo(x + 2 * (w + r), y);
        // top
        ctx.arc(x + w + r, y, r, 0, Math.PI, false);
        ctx.lineTo(x, y);
        // 添加可见的效果
        ctx.lineWidth = 1;
        ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
        ctx.strokeStyle = "rgba(255, 255, 255, 0.5)";
        ctx.stroke();
        // 和已有的图形进行异或操作
        ctx.globalCompositeOperation = "xor";
    }

    /**
     * 获取缺口坐标
     */
    let getPos = () => {
        // 背景缺口的x轴坐标
        let x = getRandomNum(this.width / 2 + this.sliderWidth, this.width - 1.5 * this.sliderWidth);
        // 滑块的偏移量
        let siOffset = getRandomNum(0.45 * this.width, 0.55 * this.width);
        // 相同的y轴高度
        let y = getRandomNum(0.5 * this.sliderWidth, this.height - 1.5 * this.sliderWidth);
        return {
            x: x,
            y: y,
            r: this.r,
            w: this.w,
            siOffset: siOffset
        }
    }

    /**
     * 获取随机数
     *
     * @param min
     * @param max
     * @returns {number}
     */
    let getRandomNum = (min, max) => {
        return Math.floor(Math.random() * (max - min + 1) + min);
    }
}
事件方法
// 控制滑块移动
sliderInput(value) {
    if (this.sliderImg == null) {
        return;
    }
    // 移动的距离
    let moveLength = value * (this.imgWidth / 100)
    let start = this.sliderImg.pos.x - this.sliderImg.pos.siOffset;
    // 控制最大位置
    if (start + moveLength >= this.imgWidth) {
        this.sliderValue = value;
    } else {
        $("#sliderImg").css("left", moveLength);
    }
},

    // 鼠标按下时, 记录当下时间
    sliderDown() {
        this.startTime = new Date().getTime();
    },

        // 是否成功的判断
        sliderChange(value) {
            // 移动的距离
            let moveLength = value * (this.imgWidth / 100) - this.sliderImg.sliderWidth / 3
            // 偏移量
            let offset = this.sliderImg.pos.siOffset;
            // 允许的误差
            let mis = 5;
            // 成功的判断
            if (Math.abs(moveLength - offset) < mis) {
                let time = ((new Date().getTime() - this.startTime) / 1000.0).toFixed(2);
                switch (true) {
                    case (time > 0 && time <= 1): {
                        this.sliderResult = "只用了" + time + "s,快如闪电!"
                        break;
                    }
                    case (time > 1 && time <= 2): {
                        this.sliderResult = "用了" + time + "s,还不错!"
                        break;
                    }
                    default: {
                        this.sliderResult = "居然使用了" + time + "s,果然持久!"
                    }
                }
                $(".z-slider-result").removeClass("z-slider-result-error").addClass("z-slider-result-success");
                // 后续成功的处理
                setTimeout(() => {
                    this.loginForm.sliderCode = this.getSliderResult(time);
                }, 500);
            } else {
                this.sliderResult = "验证失败!"
                $(".z-slider-result").removeClass("z-slider-result-success").addClass("z-slider-result-error");
                this.popoverShow();
            }
        },
相关变量
// 以下时滑动图片验证码相关
sliderValue: 0, // 滑块的值
sliderResult: "", // 验证结果
showTooltip: false, // 隐藏tooltip
imgSrc: "/imgs/test2.png", // 图片的src
popoverVisible: false, // 验证框的显示和隐藏
imgWidth: 300, // 验证码图片的宽度
imgHeight: 120,  // 验证码图片的高度
sliderImg: null, // 滑动图片验证码对象
startTime: 0, // 按下滑块的时间
使用示例:
if (this.sliderImg == null) {
    this.sliderImg = new SliderImg(this.imgWidth, this.imgHeight, 5, 10);
}
this.sliderImg.drawImg(this.imgSrc);
效果图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/909464.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ABAP 定义复杂的数据结构

最近有个需求是实现ABAP数据类型与JASON类型的转换。想要创建个ABAP的数据类型来接JASON类型是个挺麻烦的事。例如下面这个JASON数据&#xff0c;是个很简单的数据结构。但对ABAP来说有4层了&#xff0c;就有点复杂了。 不过ABAP的数据类型也是支持直接定义数据结构的嵌套的。如…

Docker之Compose

目录 前言 1.1Docker Swarm与Docker Compose 1.1.1Docker Swarm 1.1.2Docker Compose 1.1.2.1 三层容器 ​编辑 二、YAML 2.1YAML概述 2.2注意事项 2.3Docker Compose 环境安装 2.3.1下载 三、Docker-Compose配置常用字段 四、Docker-compose常用命令 五、Docker…

Ubuntu搭建CT_ICP里程计的环境暨CT-ICP部署

CT-ICP部署以及运行复现过程 0.下载资源&#xff0c;并按照github原网址的过程进行。1.查看所需要的各个部分的版本。2.安装clang编译器3.进行超级构建3.1标准进行3.2构建过程中遇到的问题 4.构建并安装CT-ICP库4.1标准进行4.2遇到的问题及解决办法 5.构建 CT-ICP 的 ROS 包装5…

工作纪实37-mybatis-plus关闭结果集输出log

1.springbootmybatis-pluslogback.xml组合&#xff0c;运行mapper会把sql查询会把结果也打印出来&#xff09;&#xff0c;但是就是不想让它输出到控制台&#xff0c;今天就来记录一下如何操作才能不把sql结果集打印出来&#xff0c;当然sql语句还是会打印的。 2、修改配置 …

bh001- Blazor hybrid / Maui 使用摄像头和扫码快速教程

1. 建立工程 bh001_camera_barcode 源码 2. 添加 nuget 包 BlazorHybrid.Maui.Permissions 因为源码比较长,主要是一些检查和申请权限相关代码,就不占用篇幅列出,感兴趣的同学直接打开源码参考 3. 添加摄像头权限 安卓 双击编辑文件,或者手工添加 <uses-permission an…

二、11.系统交互

fork 函数原型是 pid_t fork(void&#xff09;&#xff0c;返回值是数字&#xff0c;该数字有可能是子进程的 pid &#xff0c;有可能是 0&#xff0c;也有可能是-1 。 1个函数有 3 种返回值&#xff0c;这是为什么呢&#xff1f;可能的原因是 Linux 中没有获取子进程 pid 的方…

ORCA优化器浅析——DXLToPlStmt[CTranslatorDXLToPlStmt]

如上图所示是将plan_dxl转为plan_stmt的主入口函数。其主要工作就是创建plan_id_generator、motion_id_generator、param_id_generator和table_list、subplans_list&#xff0c;并将其设置到CContextDXLToPlStmt dxl_to_plan_stmt_ctxt中供后续流程调用&#xff1b;初始化CTran…

LION AI 大模型落地,首搭星纪元 ES

自新能源汽车蓬勃发展以来&#xff0c;随着潮流不断进步和变革的“四大件”有着明显变化。其中有&#xff1a;平台、智能驾驶、配置、以及车机。方方面面都有着不同程度的革新。 而车机方面&#xff0c;从以前老旧的媒体机、 CD 机发展至如今具有拓展性、开放性、智能化的车机…

Quartz任务调度框架介绍和使用

一、Quartz介绍 Quartz [kwɔːts] 是OpenSymphony开源组织在Job scheduling领域又一个开源项目&#xff0c;完全由Java开发&#xff0c;可以用来执行定时任务&#xff0c;类似于java.util.Timer。但是相较于Timer&#xff0c; Quartz增加了很多功能&#xff1a; 1.持久性作业 …

物联网(IoT)安全挑战与解决方案: 分析物联网设备面临的安全威胁,以及如何设计和管理安全的IoT生态系统

第一章&#xff1a;引言 随着科技的飞速发展&#xff0c;物联网&#xff08;IoT&#xff09;作为连接世界的桥梁&#xff0c;已经成为现代社会不可或缺的一部分。然而&#xff0c;随着IoT设备数量的不断增加&#xff0c;其安全问题也日益显著。本文将深入探讨IoT领域面临的安全…

【Ubuntu20.04安装Nvidia驱动、CUDA和CUDNN】

Ubuntu20.04安装Nvidia驱动、CUDA和CUDNN 1 Nvidia驱动安装1.1 安装1.2 安装Nvidia可能会遇到的问题1.2.1 NVIDIA 驱动与 Nouveau 驱动不兼容1.2.2 ERROR: Unable to find the development tool cc 2 CUDA安装2.1 下载和安装2.2 配置CUDA环境 3 安装CUDNN4 切换CUDA版本 1 Nvid…

min-height到底是什么?

1、概念 给元素设置最小高度&#xff0c;当height小于 min-height &#xff0c;min-height会覆盖height的值 2、案例 如果我有一个盒子A&#xff0c;A设置了min-height的高度为200px&#xff1b;并设置了overflow&#xff1a;auto&#xff0c;那么如果里面的内容超过了200px…

【经验】VScode 远程连接 Ubuntu 出错,Could not establish connection

用VScode常常会碰到以下情况&#xff0c;Could not establish connection。 先介绍一下VScode远程连接和终端SSH连接的区别&#xff1a;终端直接用SSH连接时&#xff0c;只需要开启SSH服务&#xff0c;并消耗少量的内存即可&#xff1b;VScode连接时&#xff0c;会自动在服务器…

MySQL基础篇 (三)

函数 回顾学过的函数 countavgsumminmax 数值函数 做数值运算的 演示 #ABS(X)SELECT ABS(0); #SIGN(X)SELECT SIGN(-10); #SQRT(X)SELECT SQRT(4); #LEAST(value1,value2,...)SELECT LEAST(10,20,15);字符串函数 做字符串处理&#xff08;CONCAT()&#xff09; 演示 #CO…

HCIP学习--三层架构

未完成 网关作为了一个广播域的中心出口&#xff1b;生成树的根网桥也是一棵树的中心&#xff0c;也是流量的集合点&#xff1b; 若将两者分配不同的设备将导致网络通讯资源浪费&#xff0c;故强烈建议两者在同一台汇聚层设备上 举个例子 看下图若VLAN2要去找VLAN3设备需要…

java+springboot+mysql医院预约挂号管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的医院预约挂号管理系统&#xff0c;系统包含超级管理员、管理员、医生、患者角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;用户管理&#xff1b;科室管理&#xff1b;床位管理&…

问道管理:沪指弱势震荡跌0.38%,金融、地产等板块走弱,算力概念等活跃

21日早盘&#xff0c;沪指盘中弱势震荡下探&#xff0c;创业板指一度跌逾1%失守2100点&#xff1b;北向资金小幅净流出。 截至午间收盘&#xff0c;沪指跌0.38%报3120.18点&#xff0c;深成指跌0.24%&#xff0c;创业板指跌0.62%&#xff1b;两市算计成交4238亿元&#xff0c;…

钛合金为何成为iPhone 15 Pro材料首选?

多年来&#xff0c;iPhone Pro一直采用厚重的钢框架&#xff0c;但不会持续太久。 有了iPhone 15 Pro&#xff0c;苹果可能会从钢框架转向钛框架&#xff0c;这不仅仅是因为它听起来更酷。钛比钢有很多优点&#xff0c;尤其是它更轻&#xff0c;这将解决iPhone Pro与普通iPhon…

Nvidia Jetson 编解码开发(3)解决H265解码报错“PPS id out of range”

1.问题描述 基于之前的开发程序 Nvidia Jetson 编解码开发(2)Jetpack 4.x版本Multimedia API 硬件编码开发--集成encode模块_free-xx的博客-CSDN博客 通过Jetson Xavier NX 硬编码的H265发出后, 上位机断点播放发出来的H265码流, 会报“PPS id out of range” 错误 …

有没有免费格式转换工具推荐?PDF转化为PPT的方法

在当今职场生活中&#xff0c;掌握文件格式转换技能变得异常重要。将PDF文档转换为PPT格式可以在演讲、报告等场合更好地展示和传达信息&#xff0c;为我们的专业形象增添亮点&#xff0c;接下来我们可以一起来看一下“有没有免费格式转换工具推荐?PDF转化为PPT的方法”相关的…