前言
前面的文章写过使用Canvas来模拟实现一个滑动验证功能,接下来几篇文章我计划写一个验证码的系列,会谈论如何实现各种验验证码,如随机字符串验证码、加减算术验证码、文字点选验证码等。
之前的文章有写过Canvas系列小功能文章,有兴趣的可以瞧上一瞧~
Canvas系列-下雪特效
Canvas系列-签字功能
Canvas系列-滑动验证
实现随机字符串验证功能
效果图如下,源码链接
基本思路
1、定义随机字符串,这里我们使用数字和大小写字母【0-9a-zA-Z】
2、根据传入的length参数随机生成字符串,并保存下来用于验证
3、在canvas画布中绘制随机生成的字符,然后绘制干扰线条和圆点
4、根据规则验证输入的字符串和生成的字符串是否相等
具体实现代码
// HTML
<div id="app" v-cloak>
<div class="verify-character" :style="{width: `${width}px`}">
<canvas class="canvas_character"
ref="canvas_character"
:width="width"
:height="height"
@click="reset">
</canvas>
<div class="verfify-input">
<input class="input" type="text" v-model="inputCharacter">
<button @click="reset">重新加载</button>
</div>
</div>
<button :class="['confirm', state]" @click="verify">
{{ {active:'验证', success:'验证通过', fail:'验证失败'}[state] }}
</button>
</div>
// JS
const App = {
props: {
width: {
type: Number,
default: 320
},
height: {
type: Number,
default: 60
},
length: {
type: Number,
default: 4
},
accuracy: { // 精度控制 是否判断大小写 0区分大小写
type: Number,
default: 0
}
},
data() {
return {
codeCharacter: '', // 生成字符
inputCharacter: '', // 验证字符
state: 'active', // 验证 成功 失败
}
},
mounted () {
this.init()
},
methods: {
init () {
this.$nextTick(() => {
this.ctx = this.$refs['canvas_character'].getContext('2d');
this.drawCharater();
})
},
// 绘制图形码
drawCharater () {
// this.ctx.textBaseline = 'bottom';
this.ctx.fillStyle = this.randomColor(180, 240);
this.ctx.fillRect(0, 0, this.width, this.height);
const strLen = 'ABCDEFGHIJKLMNPQRSTUVWXYZ123456789abcdefghijklmnpqrstuvwxyz';
for (let i = 0; i < this.length; i++) {
let txt = strLen[this.randomNum(0, strLen.length)];
// 随机生成字体颜色
this.ctx.fillStyle = this.randomColor(50, 160);
// 随机生成字体大小(0.5 - 0.75)高的范围
this.ctx.font = this.randomNum(this.height * 2 / 4, this.height * 3 / 4) + 'px SimHei';
// 字体对齐位置
this.ctx.textBaseline = 'top';
let x = 20 + i * (this.width / this.length);
let y = this.randomNum(5, this.height / 4);
let deg = this.randomNum(-45, 45);
this.ctx.translate(x, y);
this.ctx.rotate(deg * Math.PI / 180);
this.ctx.fillText(txt, 0, 0);
// // 恢复坐标原点和旋转角度
this.ctx.rotate(-deg * Math.PI / 180);
this.ctx.translate(-x, -y);
// 保存生成的字符串
this.codeCharacter += txt;
}
// 绘制干扰线
for (let j = 0; j < this.length; j++) {
this.ctx.strokeStyle = this.randomColor(40, 180)
this.ctx.beginPath()
this.ctx.moveTo(this.randomNum(0, this.width), this.randomNum(0, this.height))
this.ctx.lineTo(this.randomNum(0, this.width), this.randomNum(0, this.height))
this.ctx.stroke()
}
// 绘制干扰点
for (let k = 0; k < 30; k++) {
this.ctx.fillStyle = this.randomColor(0, 255)
this.ctx.beginPath()
this.ctx.arc(this.randomNum(0, this.width), this.randomNum(0, this.height), 1, 0, 2 * Math.PI)
this.ctx.fill()
}
},
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 + ')'
},
randomNum (min, max) {
return Math.floor(Math.random() * (max - min) + min)
},
reset () {
this.codeCharacter = '';
this.inputCharacter = '';
this.verifyResult = false;
this.state = 'active';
this.drawCharater();
},
verify () {
// console.log('输入>>>', this.inputCharacter)
// console.log('生成>>>', this.codeCharacter)
// console.log(this.inputCharacter === this.codeCharacter)
if (!this.inputCharacter || !this.codeCharacter) {
return
}
let result = false;
if (this.accuracy === 0) {
result = this.inputCharacter.toUpperCase() === this.codeCharacter.toUpperCase()
} else {
result = this.inputCharacter === this.codeCharacter;
}
this.state = result ? 'success' : 'fail';
this.$emit('verify', result); // 暴露给父组件使用
}
}
}
Vue.createApp(App).mount('#app');
解析:先获取画布和画笔,然后使用fillRect()
方法渲染随机颜色背景,接下来最重要的部分就是随机生成字符串并使用fillText()
方法绘制随机字符,然后使用stroke()
方法绘制线条,使用fill()
方法绘制随机分布的小圆点,最后根据需求验证即可。
结尾
上面就是【随机字符串验证码】的实现原理,代码是使用vue编写的小demo,可能存在一些兼容性问题,也没有封装成组件,但是具有一些参考意义,用于生产可以自己去封装成组件使用,完整的代码在我的GitHub仓库
本文是笔者总结编撰,如有偏颇,欢迎留言指正,若您觉得本文对你有用,不妨点个赞~