vue加canvas生成验证码

前言

最近项目中要用到验证码,就自己用canvas简单写了一个。canvas很久没用了,如果有那些不对的地点欢迎指正。

组件写了两种模式:两个数加减(计算比较简单,也可以自己加别的)和 字母数字的混合。这两种是比较常见的了,通过设置验证码的类型可以在两种模式之间进行替换

代码

<template>
    <canvas ref="canvasRef" class="verify" :width="width" :height="height" @click="drawCode"></canvas>
</template>

<script>
export default {
    props: {
        // 加减计算最小值
        min: {
            type: Number,
            default: 0
        },
        // 加减计算最大值
        max: {
            type: Number,
            default: 9
        },
        // 验证码图片的宽高
        width: {
            type: Number,
            default: 160
        },
        height: {
            type: Number,
            default: 60
        },
        // 验证码的类型
        verifyType: {
            type: String,
            default: 'default',
            validator: (val) => {
                // default数字和小写字母混合
                // cal   两个数加减
                return ['default','cal'].includes(val);
            }
        },
        // 字母字符串的长度
        strLength: {
            type: Number,
            default: 5
        },
        // 背景色
        bg: {
            type: String,
            default: '#ffffff'
        }
    },
    data() {
        return {
            // 操作符号  只计算加减
            operator: [1,-1],
            // code集合
            codeList: [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'],
            // 结果
            result: undefined
        };
    },
    mounted() {
        this.drawCode();
        this.adjustWindow(this.$refs.canvasRef);
    },
    methods: {
        // 绘制验证码
        drawCode() {
            // 获取对象
            let canvas = this.$refs.canvasRef;
            // 创建画布环境
            let context = canvas.getContext('2d');
            context.clearRect(0,0,this.width,this.height);
            // 绘制背景
            context.fillStyle = this.bg;
            // 清空画布
            context.fillRect(0,0,this.width,this.height);
            // 绘制80个点
            for(let i = 0;i < 80;i++) {
                this.drawPoint(context);
            }
            // 绘制内容
            context.strokeStyle = this.randColor();
            // 文字大小为高的一半,并随即加减-5~10
            let fontSize = parseInt(this.height / 2) + this.randomNum(-5,10);
            // 字体
            context.font = `${fontSize}px 楷体`;
            // 文字内容
            let textContent = this.createContent();
            // 计算文字偏移量
            let textX = parseInt((this.width - context.measureText(textContent).width) / 2) ;

            // 设置文字旋转
            let angle = this.randomNum(-8,8);
            context.rotate(Math.PI / 180 * -angle);
            context.strokeText(textContent, textX, parseInt(this.height / 1.5));
            context.rotate(Math.PI / 180 * angle);

            // 向父组件返回结果
            this.$emit('getResult',this.result);
        },
        // 绘制点
        drawPoint(context) {
            // 获取点的随机颜色
            context.fillStyle = this.randColor();
            context.beginPath();
            // 生成随机圆心
            let x = this.randomNum(0,this.width);
            let y = this.randomNum(0,this.height);
            // 生成随机半径
            let r = Math.random();
            // 生成圆环
            context.arc(x,y,r,0,Math.PI * 2,true);
            context.closePath();
            // 填充圆
            context.fill();
        },
        // 生成绘制内容
        createContent() {
            let str = '';
            // 判断类型
            if(this.verifyType == 'default') {
                // 绘制文字和数字的组合
                for(let i = 0;i < this.strLength;i++) {
                    let i = this.randomNum(0,35);
                    str += this.codeList[i] + ' ';
                }
                this.result = str;
            }else{
                // 加减
                let num1 = this.randomNum(this.min,this.max);
                let num2 = this.randomNum(this.min,this.max);
                let op = this.operator[this.randomNum(0,1)];
                // 计算结果
                this.result = num1 + op * num2;
                str = num1 + (op > 0 ? ' + ' : ' - ') + num2 + ' = ?';
            }
            //
            return str;
        },
        // 生成从minNum到maxNum的随机数
        randomNum(minNum,maxNum) {
            switch(arguments.length) {
                case 1:
                    return parseInt(Math.random() * minNum + 1,10);
                case 2:
                    return parseInt(Math.random() * (maxNum - minNum + 1) + minNum,10);
                default:
                    return 0;
            }
        },
        // 生成随机颜色
        randColor() {
            let r = this.randomNum(255);
            let g = this.randomNum(255);
            let b = this.randomNum(255);
            return `rgb(${r},${g},${b})`;
        },
        adjustWindow (dom) {
            // 获取屏幕参数
            let screen = window.screen;
            // 屏幕比例
            let screenZoom = screen.width / 1920;
            // 窗口比例
            let windowZoom = window.innerWidth / window.outerWidth;
            // 这里要考虑浏览器是否全屏的
            if(screen.width > window.outerWidth) {
                // 此时浏览器非全屏
                windowZoom = window.outerWidth / screen.width;
            }
            // 保留3位小数
            let zoom = parseFloat((screenZoom * windowZoom).toFixed(3));
            // 改变dom的style
            dom.style.zoom = zoom;


            // 监听窗口的变化
            window.addEventListener('resize', () => {
                // 屏幕比例
                screenZoom = screen.width / 1920;
                // 窗口比例
                windowZoom = window.innerWidth / window.outerWidth;
                // 这里要考虑浏览器是否全屏的
                if(screen.width > window.outerWidth) {
                    // 此时浏览器非全屏
                    windowZoom = window.outerWidth / screen.width;
                }
                // 保留三位小数
                zoom = parseFloat((screenZoom * windowZoom).toFixed(3));
                // 改变dom的style
                dom.style.zoom = zoom;
            });
        }
    }
};
</script>

<style scoped lang="scss">
.verify{
  cursor:pointer;
}
</style>

效果

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无知的小菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值