前端验证码实现
主体思路,使用canvas画布生成验证码,跟输入框内数据通过from表单进行对比
代码
//rules判断
rules: [{ validator: validateCode, trigger: 'change' }],
//validateCode方法内容validateCode(rule, value, callback) {if (value == '') {callback(new Error('验证码不能为空'))} else if (value !== this.identifyCode) {callback(new Error('验证码错误!'))} else {callback()}},//组件化------验证码封装后的页面引入
<verificationPage :identifyCode="identifyCode" style="cursor: pointer" @click.native="getCode()" />//date中要声明identifyCode这个变量,用于对比输入的值与验证码页面生成的验证码是否一致identifyCode: '',//getCode方法触发验证码的生成与重新生成
//(这个方法在页面dom元素加载完时就需要调用一次,让验证码页面生成一个验证码)getCode() {var a = ['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',]var code = ''for (var i = 0; i < 4; i++) {//0-1的随机小数 --> 0~数组长度-1的范围 取整var randPosition = Math.floor(Math.random() * (a.length - 1)) //每次生成一个随机数的位置code += a[randPosition] //带有随机位置作为下标,指示到当前随机产生的某个字符上,}this.identifyCode = code},
验证码组件页面代码
<template><div class="s-canvas" style="display: inline"><canvasid="s-canvas":width="contentWidth":height="contentHeight"></canvas></div>
</template><script>
export default {name: "SIdentify",props: {identifyCode: {// 默认注册码type: String,default: "1234",},fontSizeMin: {// 字体最小值type: Number,default: 25,},fontSizeMax: {// 字体最大值type: Number,default: 35,},backgroundColorMin: {// 验证码图片背景色最小值type: Number,default: 200,},backgroundColorMax: {// 验证码图片背景色最大值type: Number,default: 220,},dotColorMin: {// 背景干扰点最小值type: Number,default: 60,},dotColorMax: {// 背景干扰点最大值type: Number,default: 120,},contentWidth: {// 容器宽度type: Number,default: 117,},contentHeight: {// 容器高度type: Number,default: 32,},},methods: {// 生成一个随机数randomNum(min, max) {return Math.floor(Math.random() * (max - min) + min);},// 生成一个随机的颜色randomColor(min, max) {let r = this.randomNum(min, max);let g = this.randomNum(min, max);let b = this.randomNum(min, max);return "rgb(" + r + "," + g + "," + b + ")";},drawPic() {let canvas = document.getElementById("s-canvas");let ctx = canvas.getContext("2d");ctx.textBaseline = "bottom";// 绘制背景ctx.fillStyle = "#e6ecfd";ctx.fillRect(0, 0, this.contentWidth, this.contentHeight);// 绘制文字for (let i = 0; i < this.identifyCode.length; i++) {this.drawText(ctx, this.identifyCode[i], i);}this.drawLine(ctx);this.drawDot(ctx);},drawText(ctx, txt, i) {ctx.fillStyle = this.randomColor(50, 160); // 随机生成字体颜色ctx.font =this.randomNum(this.fontSizeMin, this.fontSizeMax) + "px SimHei"; // 随机生成字体大小let x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1));let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5);var deg = this.randomNum(-30, 30);// 修改坐标原点和旋转角度ctx.translate(x, y);ctx.rotate((deg * Math.PI) / 180);ctx.fillText(txt, 0, 0);// 恢复坐标原点和旋转角度ctx.rotate((-deg * Math.PI) / 180);ctx.translate(-x, -y);},drawLine(ctx) {// 绘制干扰线for (let i = 0; i < 4; i++) {ctx.strokeStyle = this.randomColor(100, 200);ctx.beginPath();ctx.moveTo(this.randomNum(0, this.contentWidth),this.randomNum(0, this.contentHeight));ctx.lineTo(this.randomNum(0, this.contentWidth),this.randomNum(0, this.contentHeight));ctx.stroke();}},drawDot(ctx) {// 绘制干扰点for (let i = 0; i < 30; i++) {ctx.fillStyle = this.randomColor(0, 255);ctx.beginPath();ctx.arc(this.randomNum(0, this.contentWidth),this.randomNum(0, this.contentHeight),1,0,2 * Math.PI);ctx.fill();}},},watch: {identifyCode() {this.drawPic();},},mounted() {this.drawPic();},
};
</script>