先上圖

接下來樓一眼實現代碼
這里說明一下,我用到了vue3.0,vant3.0以及阿里圖標,vant 很人性化針對vue3.0新出了個vant3.0版本,阿里則是適配vue3.0的。我們將verify驗證碼進行了封裝,內部用進行了hook以及工具的封裝。
登錄頁代碼 login.vue
<template> <div class="login"> <span class="iconfont icongouwuche"></span> <van-form @submit="onSubmit"> <van-field v-model="username" name="username" label="用戶名" placeholder="用戶名" :rules="[{ required: true, message: '請填寫用戶名' }]" /> <van-field v-model="password" type="password" name="password" label="密碼" placeholder="密碼" :rules="[{ required: true, message: '請填寫密碼' }]" /> <van-field center clearable label="驗證碼" placeholder="輸入驗證碼" v-model="verify" > </van-field> <ImgVerify ref="verifyRef" /> <div style="margin: 16px"> <van-button round block color="#1baeae" native-type="submit"> 登錄</van-button > </div> </van-form> </div> </template> <script> import { reactive, ref, toRefs } from "vue"; import ImgVerify from "@/components/ImgVerify"; export default { components: { ImgVerify }, setup(props, con) { const verifyRef = ref(null); const state = reactive({ username: "", password: "", verify: "", }); const onSubmit = (values) => { if (state.verify.toLowerCase() == verifyRef.value.imgCode.toLowerCase()) { // 提交時判斷是否是正確驗證碼 alert("輸入正確"); TODO; // } }; return { ...toRefs(state), onSubmit, verifyRef, }; }, }; </script> <style lang='scss' scoped> .login { /* background: #eee; */ } div { font-size: 14px; .icongouwuche { padding-top: 40px; font-size: 120px; } } </style>
驗證碼組件 ImgVerify.vue
這里只是簡單地獲取以及排版,正正的邏輯放到了hook中
<template>
<div>
<canvas
ref="verify"
:width="width"
:height="height"
@click="handleDraw"
></canvas>
</div>
</template>
<script>
import {ref } from "vue";
import {setVerify} from '../hooks/Verify'
export default {
setup(props, con) {
const verify = ref(null);
return{
...setVerify(verify)
}
},
};
</script>
<style lang='scss' scoped>
</style>
我們先看一下封裝好的tool工具函數。
Tool.js
//隨機數 export function randomNum(min, max) { return parseInt(Math.random() * (max - min + 1) + min); }; //隨機顏色 export function randomColor(min, max) { const r = randomNum(min, max); const g = randomNum(min, max); const b = randomNum(min, max); return `rgb(${r},${g},${b})`; };
接下來重頭戲實現驗證碼
verify.js
import { onMounted, toRefs, reactive } from "vue";
import { randomColor, randomNum } from '../utils/Tools'
export function setVerify(verify) {
const state = reactive({
pool: "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", // 隨機字符串
width: 120, //展示區域寬度
height: 40, //展示區域高度
imgCode: "", //保存頁面的內容(用來判斷輸入驗證是否滿足改code)
});
// 1、初始展示
onMounted(() => {
draw();
state.imgCode = draw();
});
// 2、點擊圖片重新繪制
const handleDraw = () => {
draw();
state.imgCode = draw();
};
// 3、繪制隨機內容
const draw = () => {
/*
* 一、填充顏色
* 1、生成畫布
* 2、填充顏色與位置
* 3、填充位置
*/
const ctx = verify.value.getContext("2d");
ctx.fillStyle = randomColor(180, 230);
ctx.fillRect(0, 0, state.width, state.height);
/*
* 二、生成4個隨機數
* 1、七扭八歪
* 2、隨機大小
* 3、畫吧柳梢,各種色兒
*/
let imgCode = "";
for (let i = 0; i < 4; i++) {
const text = state.pool[randomNum(0, state.pool.length - 1)];
const fontSize = randomNum(18, 40);
const deg = randomNum(-30, 30);
/*
* 繪制文字並讓四個文字在不同的位置顯示的思路 :
* 1、定義字體
* 2、定義對齊方式
* 3、填充不同的顏色
* 4、保存當前的狀態(以防止以上的狀態受影響)
* 5、平移translate()
* 6、旋轉 rotate()
* 7、填充文字
* 8、restore出棧
* */
ctx.font = fontSize + "px Simhei";
ctx.textBaseline = "top";
ctx.fillStyle = randomColor(80, 150);
ctx.save();
ctx.translate(30 * i + 15, 15);
ctx.rotate((deg * Math.PI) / 180);
ctx.fillText(text, -15 + 5, -15);
ctx.restore();
imgCode += text;
}
/*
* 三、隨機產生5條干擾線,干擾線的顏色要淺一點
*/
for (let i = 0; i < 5; i++) {
ctx.beginPath();
ctx.moveTo(randomNum(0, state.width), randomNum(0, state.height));
ctx.lineTo(randomNum(0, state.width), randomNum(0, state.height));
ctx.strokeStyle = randomColor(180, 230);
ctx.closePath();
ctx.stroke();
}
/*
* 四、隨機產生40個干擾的小點
*/
for (let i = 0; i < 40; i++) {
ctx.beginPath();
ctx.arc(
randomNum(0, state.width),
randomNum(0, state.height),
1,
0,
2 * Math.PI
);
ctx.closePath();
ctx.fillStyle = randomColor(150, 200);
ctx.fill();
}
return imgCode;
};
return {
...toRefs(state),
handleDraw,
verify,
};
}
一個vscode快熟生成vue3代碼片段的方法
1、選擇 文件---》首選項---》代碼片段---》
2、新建json

3、配置json
"Print to console": { "prefix": "vue3", "body": [ "<template>", "<div>", "", "</div>", "</template>", "", "<script>", "export default {", " components: {},", " setup(props,con){}", "}", "</script>", "", "<style lang='scss' scoped>", "", "</style>", "$2" ], "description": "Vue3模板" }

