验证码组件
<template>
<div class="s-draw">
<canvas ref="canvasRef" :width="contentWidth" :height="contentHeight"></canvas>
</div>
</template>
<script>
import { ref, onMounted, watch } from 'vue';
export default {
name: 'SIdentify',
props: {
identifyCode: {
type: String,
default: '1234',
},
fontSizeMin: {
type: Number,
default: 25,
},
fontSizeMax: {
type: Number,
default: 30,
},
backgroundColorMin: {
type: Number,
default: 255,
},
backgroundColorMax: {
type: Number,
default: 255,
},
colorMin: {
type: Number,
default: 0,
},
colorMax: {
type: Number,
default: 160,
},
lineColorMin: {
type: Number,
default: 100,
},
lineColorMax: {
type: Number,
default: 255,
},
dotColorMin: {
type: Number,
default: 0,
},
dotColorMax: {
type: Number,
default: 255,
},
contentWidth: {
type: Number,
default: 132,
},
contentHeight: {
type: Number,
default: 31,
},
},
setup(props) {
const canvasRef = ref(null);
// 生成一个随机数
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 = canvasRef.value;
let ctx = canvas.getContext('2d');
ctx.textBaseline = 'bottom';
// 绘制背景
ctx.fillStyle = randomColor(props.backgroundColorMin, props.backgroundColorMax);
ctx.fillRect(0, 0, props.contentWidth, props.contentHeight);
// 绘制文字
for (let i = 0; i < props.identifyCode.length; i++) {
drawText(ctx, props.identifyCode[i], i);
}
drawLine(ctx);
drawDot(ctx);
};
const drawText = (ctx, txt, i) => {
ctx.fillStyle = randomColor(props.colorMin, props.colorMax);
ctx.font = randomNum(props.fontSizeMin, props.fontSizeMax) + 'px SimHei';
let x = (i + 1) * (props.contentWidth / (props.identifyCode.length + 1));
let y = randomNum(props.fontSizeMax, props.contentHeight - 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 < 8; i++) {
ctx.strokeStyle = randomColor(props.lineColorMin, props.lineColorMax);
ctx.beginPath();
ctx.moveTo(randomNum(0, props.contentWidth), randomNum(0, props.contentHeight));
ctx.lineTo(randomNum(0, props.contentWidth), randomNum(0, props.contentHeight));
ctx.stroke();
}
};
// 绘制点
const drawDot = (ctx) => {
for (let i = 0; i < 100; i++) {
ctx.fillStyle = randomColor(props.dotColorMin, props.dotColorMax);
ctx.beginPath();
ctx.arc(randomNum(0, props.contentWidth), randomNum(0, props.contentHeight), 1, 0, 2 * Math.PI);
ctx.fill();
}
};
// 监听 identifyCode 的变化
watch(() => props.identifyCode, () => {
drawPic();
});
onMounted(() => {
drawPic();
});
return {
canvasRef,
};
},
};
</script>
<style scoped>
.s-draw {
height: 38px;
}
.s-draw canvas {
margin-top: 5px;
margin-left: 8px;
}
</style>
页面使用组件
<template>
<div id="atilposition">
<input
type="text"
v-model="inputCode"
placeholder="请输入验证码"
clearable
/>
<span :onClick="createCode" id="spancode">
<aCaptcha :identifyCode="code"></aCaptcha>
</span>
</div>
</template>
页面引用组件
import aCaptcha from "@/components/aCaptcha.vue";
页面内方法
export default {
name: 'Login',
components:{
aCaptcha
},
setup(){
const code = ref('');
const inputCode = ref('');
const createCode = () => {
let text = '';
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 4; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
code.value = text;
};
const login = () =>{
if (inputCode.value === '') {
top.$messages.push({t:new Date().getTime(),m:t('tips.login.captchaEnter')})
return
}
if (inputCode.value.toLowerCase() !== code.value.toLowerCase()) {
top.$messages.push({t:new Date().getTime(),m:t('tips.login.captchaError')})
inputCode.value = '';
createCode();
return
}
}
//校验验证码
onMounted(()=>{
createCode()
})
return {
code,
inputCode,
login,
createCode
}
}
}