js+canvas生成验证码
代码示例
js部分
代码如下(示例):
<template>
<div class="s-canvas">
<canvas id="s-canvas" :width="contentWidth" :height="contentHeight"></canvas>
</div>
</template>
<script setup>
import {onMounted, watch} from "vue";
const props = defineProps({
identifyCode: {
type: String,
default: '1234'
},
fontSizeMin: {
type: Number,
default: 28
},
fontSizeMax: {
type: Number,
default: 40
},
backgroundColorMin: {
type: Number,
default: 180
},
backgroundColorMax: {
type: Number,
default: 240
},
colorMin: {
type: Number,
default: 50
},
colorMax: {
type: Number,
default: 160
},
lineColorMin: {
type: Number,
default: 40
},
lineColorMax: {
type: Number,
default: 180
},
dotColorMin: {
type: Number,
default: 0
},
dotColorMax: {
type: Number,
default: 255
},
contentWidth: {
type: Number,
default: 112
},
contentHeight: {
type: Number,
default: 40
}
})
// 生成一个随机数
function randomNum (min, max) {
return Math.floor(Math.random() * (max - min) + min)
}
// 生成一个随机的颜色
function randomColor (min, max) {
let r = randomNum(min, max)
let g = randomNum(min, max)
let b = randomNum(min, max)
return 'rgb(' + r + ',' + g + ',' + b + ')'
}
function drawPic () {
var canvas = document.getElementById('s-canvas')
var 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)
}
function 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)
let deg = randomNum(-30, 30)
// 修改坐标原点和旋转角度
ctx.translate(x, y)
ctx.rotate(deg * Math.PI / 270)
ctx.fillText(txt, 0, 0)
// 恢复坐标原点和旋转角度
ctx.rotate(-deg * Math.PI / 270)
ctx.translate(-x, -y)
}
function drawLine (ctx) {
// 绘制干扰线
for (let i = 0; i < 2; 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()
}
}
function drawDot (ctx) {
// 绘制干扰点
for (let i = 0; i < 20; i++) {
ctx.fillStyle = randomColor(0, 255)
ctx.beginPath()
ctx.arc(
randomNum(0, props.contentWidth),
randomNum(0, props.contentHeight),
1,
0,
2 * Math.PI
)
ctx.fill()
}
}
watch(() => props.identifyCode, () => {
drawPic()
})
onMounted(() => {
drawPic()
})
</script>
<style lang='scss' scoped>
.s-canvas {
height: 38px;
cursor: pointer;
}
.s-canvas canvas{
margin-top: 1px;
//margin-left: 8px;
}
</style>
父组件调用
<script setup>
import {computed, reactive, ref} from "vue";
import SlideVerify from "./SlideVerify.vue";
const emits = defineEmits(['update:dialogVisible','defeated', 'confirm'])
const props = defineProps({
dialogVisible: {
type: Boolean,
default: false
}
})
const form = ref()
const dialogVisible = computed({
get: () => props.dialogVisible,
set: (value) => {
emits('update:dialogVisible', value)
}
})
const data = reactive({
identifyCode: '',
identifyCodes: '1234567890abcdefghijklmnopqrstuvwxyz',
formLabelAlign: {
verifyCode: '',
}
})
function randomNum(min, max) {
return Math.floor(Math.random() * (max - min) + min)
}
// 切换验证码
function refreshCode() {
data.identifyCode = ''
makeCode(data.identifyCodes, 4)
}
refreshCode()
// 生成随机验证码
function makeCode(o, l) {
for (let i = 0; i < l; i++) {
data.identifyCode += data.identifyCodes[
Math.floor(Math.random() * (data.identifyCodes.length))
]
}
}
/* 自定义验证码规则 */
const validateVerifycode = (rule, value, callback) => {
if (!value) {
callback(new Error('请输入验证码'))
} else if (value !== data.identifyCode) {
callback(new Error('验证码不正确!'))
emits('defeated')
} else {
callback()
}
}
const rules = {
verifyCode: [
{
required: true,
trigger: 'blur',
validator: validateVerifycode
}
]
}
// 验证
const confirm = () => {
form.value.validate((valid) => {
if (valid){
emits('confirm')
dialogVisible.value = false
}
})
}
const open = () => {
refreshCode()
}
</script>
<template>
<div class="slide-verify">
<div>
<SlideVerify :identifyCode="data.identifyCode"></SlideVerify>
</div>
<div class="button-wrap">
<el-button @click="refreshCode" type='text' class="textbtn">看不清,换一张</el-button>
</div>
</div>
</template>
<style lang='scss' scoped>
.slide-verify {
display: flex;
.button-wrap {
display: flex;
align-items: center;
}
.textbtn {
margin-left: 30px;
}
}
</style>