滑动验证码-elementui实现

使用elementui框架实现

html代码
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>
主要代码:
javascript 复制代码
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);
    }
}
事件方法
javascript 复制代码
// 控制滑块移动
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();
            }
        },
相关变量
javascript 复制代码
// 以下时滑动图片验证码相关
sliderValue: 0, // 滑块的值
sliderResult: "", // 验证结果
showTooltip: false, // 隐藏tooltip
imgSrc: "/imgs/test2.png", // 图片的src
popoverVisible: false, // 验证框的显示和隐藏
imgWidth: 300, // 验证码图片的宽度
imgHeight: 120,  // 验证码图片的高度
sliderImg: null, // 滑动图片验证码对象
startTime: 0, // 按下滑块的时间
使用示例:
javascript 复制代码
if (this.sliderImg == null) {
    this.sliderImg = new SliderImg(this.imgWidth, this.imgHeight, 5, 10);
}
this.sliderImg.drawImg(this.imgSrc);
效果图
相关推荐
永乐春秋36 分钟前
WEB攻防-通用漏洞&文件上传&js验证&mime&user.ini&语言特性
前端
鸽鸽程序猿37 分钟前
【前端】CSS
前端·css
ggdpzhk39 分钟前
VUE:基于MVVN的前端js框架
前端·javascript·vue.js
小曲曲2 小时前
接口上传视频和oss直传视频到阿里云组件
javascript·阿里云·音视频
学不会•3 小时前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
EasyNTS4 小时前
H.264/H.265播放器EasyPlayer.js视频流媒体播放器关于websocket1006的异常断连
javascript·h.265·h.264
活宝小娜5 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点5 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow5 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o5 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app