⭐前言
在vue项目中,登录界面必不可少。简单项目里,验证码通常由数字字母构成。一般有两种产生方式:前端,后端。后端生成,前端直接调用接口,将返回的url放入a标签即可。而前端生成,则大多用canvas画布实现,如何让验证码随屏幕大小变化,还能保持原样不失真,这就是我们要实现的功能。当然,在创建vue项目时,我们必须得克服跨域问题。No ' Access-Control-Allow-Origin'的解决方案,在文章最后。若有错误和建议,请积极指正!
⭐canvas 生成验证码 (vue)
按照需求,一步步实现验证码生成。(源码贴在后面)
下面,进入正题。
组件需要什么?
首先,我们自己注册一个组件 Identify.vue
,用来实现验证码的生成。
第一步, 我们要明确,这个组件需要什么?
显然,我们需要一个画布,在画布上进行绘制,生成验证码就好。
自然而然,
<canvas></canvas>
就布局上去了。
<template> <div > <canvas id="canvas" ></canvas> </div></template>
再者,我们需定义组件属性
props: { identifyCode: { // 默认注册码 type: String, default: '1234' }, fontSizeMin: { // 字体最小值 type: Number, default: 130 }, fontSizeMax: { // 字体最大值 type: Number, default: 140 }}
组件的实现
接下来,我们可以进行绘制验证码。内容包括如下:
1、随机数(验证码内容:一般为数字字母组合)
2、随机颜色 (rgb实现)
3、干扰线
4、干扰点
随机数
randomNum (min, max) { return Math.floor(Math.random() * (max - min) + min)},
随机色
randomColor (min, max) { const r = this.randomNum(min, max) const g = this.randomNum(min, max) const b = this.randomNum(min, max) return 'rgb(' + r + ',' + g + ',' + b + ')'},
干扰线
drawLine (ctx) { const canvas = document.getElementById('canvas') for (let j = 0; j < 4; j++) { ctx.strokeStyle = this.randomColor(100, 200) ctx.beginPath() ctx.moveTo(this.randomNum(0, canvas.width), this.randomNum(0, canvas.height)) ctx.lineTo(this.randomNum(0, canvas.width), this.randomNum(0, canvas.height)) // lineWidth 控制线的粗细 ctx.lineWidth = 3 ctx.stroke() }},
干扰点
drawDot (ctx) { const canvas = document.getElementById('canvas') for (let k = 0; k < 30; k++) { ctx.fillStyle = this.randomColor(0, 255) ctx.beginPath() // 可以改变 3 来实现改变干扰点的大小 ctx.arc(this.randomNum(0, canvas.width), this.randomNum(0, canvas.height), 3, 0, 2 * Math.PI) ctx.fill() }}
绘制验证码
drawPic () { const canvas = document.getElementById('canvas') const ctx = canvas.getContext('2d') ctx.textBaseline = 'bottom' // console.log(canvas.width) // 绘制背景(颜色) ctx.fillStyle = '#e6ecfd' ctx.fillRect(0, 0, canvas.width, canvas.height) // 绘制文字 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) { const canvas = document.getElementById('canvas') ctx.fillStyle = this.randomColor(50, 160) // 随机生成字体颜色 ctx.font = this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei' // 随机生成字体大小 // x,y控制生成字体在画布上分布的位置。如下的0.5/1,可根据实际情况进行增减。 const x = (i + 0.5 ) * (canvas.width / (this.identifyCode.length + 1)) const y = this.randomNum(this.fontSizeMax, canvas.height - 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)},
注意:
const canvas = document.getElementById('canvas')// canvas.width是为了获取到画布的宽度,实现适配。高度亦是如此。
组件源码
原理搞懂,直接上手。新建一个vue文件。
Identify.vue
代码如下:
<template> <div > <canvas id="canvas" ></canvas> </div></template><script>export default { name: 'Identify', props: { identifyCode: { // 默认注册码 type: String, default: '1234' }, fontSizeMin: { // 字体最小值 type: Number, default: 130 }, fontSizeMax: { // 字体最大值 type: Number, default: 140 } }, methods: { // 生成一个随机数 randomNum (min, max) { return Math.floor(Math.random() * (max - min) + min) }, // 生成一个随机的颜色 randomColor (min, max) { const r = this.randomNum(min, max) const g = this.randomNum(min, max) const b = this.randomNum(min, max) return 'rgb(' + r + ',' + g + ',' + b + ')' }, drawPic () { const canvas = document.getElementById('canvas') const ctx = canvas.getContext('2d') ctx.textBaseline = 'bottom' // console.log(canvas.width) // 绘制背景 ctx.fillStyle = '#e6ecfd' ctx.fillRect(0, 0, canvas.width, canvas.height) // 绘制文字 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) { const canvas = document.getElementById('canvas') ctx.fillStyle = this.randomColor(50, 160) // 随机生成字体颜色 ctx.font = this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei' // 随机生成字体大小 const x = (i + 0.5 ) * (canvas.width / (this.identifyCode.length + 1)) const y = this.randomNum(this.fontSizeMax, canvas.height - 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) { // 绘制干扰线 const canvas = document.getElementById('canvas') for (let j = 0; j < 4; j++) { ctx.strokeStyle = this.randomColor(100, 200) ctx.beginPath() ctx.moveTo(this.randomNum(0, canvas.width), this.rando.........