Vue3 生成图片验证码组件

5,098 阅读1分钟

突然用到图片验证码,从其他论坛上东拼西凑出本地前端生成验证码图片的组件,做一下笔记。

1、安装依赖

需要用到【identify】和【md5】

其中【md5】主要的作用是用于验证码正确值加密使用

npm install identify
npm install md5

2、组件部分

此处使用到canvas

<template>
 <div class="s-canvas">
  <canvas id="s-canvas" :width="contentWidth" :height="contentHeight"></canvas>
 </div>
</template>

<script>
	import md5 from 'js-md5'
	import {
		toRefs,
		onMounted,
		watch,
		defineComponent
	} from 'vue'

	export default defineComponent({
		name: 'imageCode',
		props: {
			change: { // 刷新验证码使用
				type: Boolean,
				default: false
			},
			contentWidth: { // 验证码图片宽
				type: Number,
				default: 112
			},
			contentHeight: { // 验证码图片高
				type: Number,
				default: 38
			}
		},
		emits: ["getCode"], // 返回验证码加密正确值的函数
		setup(props, context) {
                        // 默认值 
			const defaultData = {
				identifyCode: '', // 验证码值,未加密的
				identifyCodes: '1234567890', // 生成验证码的元素,可以加入字母
				fontSizeMin: 20, // 图片上验证文字的最小值
				fontSizeMax: 40, // 图片上验证文字的最小值
				backgroundColorMin: 180, // 图片背景色值最小
				backgroundColorMax: 240, // 图片背景色值最大
				colorMin: 50, // 文字色值最小
				colorMax: 160, // 文字色值最大
				lineColorMin: 40, // 干扰线色值最小
				lineColorMax: 120, // 干扰线色值最大
				dotColorMin: 0, // 干扰点色值最小
				dotColorMax: 255, // 干扰点色值最大
                                lineSum: 4, // 干扰线数量
                                dotSum: 40, // 干扰点数量
			}
                        // 父级传递
			const {
				contentWidth,
				contentHeight,
				change
			} = toRefs(props)

			// 生成一个随机数
			const randomNum = (min, max) => {
				return Math.floor(Math.random() * (max - min) + min)
			}

			// 生成一个随机的颜色
			const randomColor = (min, max) => {
				let r = randomNum(min, max)
				let g = randomNum(min, max)
				let b = randomNum(min, max)
				return 'rgb(' + r + ',' + g + ',' + b + ')'
			}

			// 创建图形
			const drawPic = () => {
				let canvas = document.getElementById('s-canvas')
				let ctx = canvas.getContext('2d')
				ctx.textBaseline = 'bottom'
				// 绘制背景
				ctx.fillStyle = randomColor(defaultData.backgroundColorMin, defaultData.backgroundColorMax)
				ctx.fillRect(0, 0, contentWidth.value, contentHeight.value)
				// 绘制文字
				for (let i = 0; i < defaultData.identifyCode.length; i++) {
					drawText(ctx, defaultData.identifyCode[i], i)
				}
				drawLine(ctx)
				drawDot(ctx)
			}

			// 绘制文字
			const drawText = (ctx, txt, i) => {
				ctx.fillStyle = randomColor(defaultData.colorMin, defaultData.colorMax)
				ctx.font = randomNum(defaultData.fontSizeMin, defaultData.fontSizeMax) + 'px SimHei'
				let x = (i + 1) * (contentWidth.value / (defaultData.identifyCode.length + 1))
				let y = randomNum(defaultData.fontSizeMax, contentHeight.value - 5)
				var deg = randomNum(-45, 45)
				// 修改坐标原点和旋转角度
				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 drawLine = (ctx) => {
				for (let i = 0; i < 4; i++) {
					ctx.strokeStyle = randomColor(defaultData.lineColorMin, defaultData.lineColorMax)
					ctx.beginPath()
					ctx.moveTo(randomNum(0, contentWidth.value), randomNum(0, contentHeight.value))
					ctx.lineTo(randomNum(0, contentWidth.value), randomNum(0, contentHeight.value))
					ctx.stroke()
				}
			}
			// 绘制干扰点
			const drawDot = (ctx) => {
				for (let i = 0; i < 60; i++) {
					ctx.fillStyle = randomColor(0, 255)
					ctx.beginPath()
					ctx.arc(randomNum(0, contentWidth.value), randomNum(0, contentHeight.value), 1, 0, 2 * Math
						.PI)
					ctx.fill()
				}
			}

			// 生成图片
			const makeCode = () => {
				defaultData.identifyCode = "";
				for (let i = 0; i < 4; i++) {
					defaultData.identifyCode += defaultData.identifyCodes[						randomNum(0, defaultData.identifyCodes.length)					];
				}
                                
                                // 绘制图片
				drawPic()
                                // 返回加密后的图片验证码值
				context.emit('getCode', md5(defaultData.identifyCode))
			}
                        
                        // 初识函数,生成图片 
			onMounted(() => {
				makeCode()
			})

                        // 监听change变化,重新生成图片
			watch(change, () => {
				makeCode()
			})

		}
	})
</script>

3、调用组件

1、引入组件
import imageCode from '../../../components/ImageCode.vue';
2、使用
<image-code :change="data.change_img_code" @click="changeImageCode" @getCode="backImageCode"></image-code>
3、script

	export default {
		name: '',
		components: {
			imageCode
		},
		setup(){
			const data = reactive({
				change_img_code: false, // 刷新验证码
				img_code:'',// 加密后的验证码值
			})
                        
                        // 刷新验证码操作
			const changeImageCode = ()=> {
				data.change_img_code = !data.change_img_code
			}
			
                        // 接收组件返回加密后的验证码值
			const backImageCode = (code) =>{
				data.img_code = code
				console.log('data',data.img_code)
			}
			
			return {
				changeImageCode,
				backImageCode,
				data
			}
		}
	}