vue3純前端實(shí)現(xiàn)驗(yàn)證碼代碼示例
前言
- 驗(yàn)證碼的用途:通過要求用戶輸入一串難以被機(jī)器自動識別的字符或圖像,有效阻止惡意用戶或腳本通過暴力方式嘗試登錄賬戶。
- 驗(yàn)證碼的分類:常見的驗(yàn)證碼有短信、文本、圖形等,安全度越高,依賴的插件或服務(wù)也越多。
今天我們來做一個(gè)簡單的純前端字符驗(yàn)證碼碼組件,不需要插件,僅做為示例。
先看一下效果:
分析
一個(gè)簡單的字符驗(yàn)證碼,只需求定義一個(gè)字符集,一個(gè)隨機(jī)生成函數(shù)就可以了。如果要再進(jìn)一步增加一些效果,如干擾線,干擾點(diǎn),則需要借助Canvas
來進(jìn)行繪制,以增強(qiáng)可視化效果。
基礎(chǔ)代碼示例
以下代碼就完成了簡單驗(yàn)證碼的核心工作,生成指定位數(shù)的隨機(jī)驗(yàn)證碼。
// 生成校驗(yàn)碼 const makeCode = (len = 4) => { let code = ""; const codeLength = len; //驗(yàn)證碼的長度 // 定義生成驗(yàn)證碼的字符集,去除易混淆的字符集1il0oO const identifyCodes = "123456789abcdefjhijkinpqrsduvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; for (let i = 0; i < codeLength; i++) { // 獲取隨機(jī)字符 code += identifyCodes[randomNum(0, identifyCodes.length)]; } return code; //把code值賦給驗(yàn)證碼 }; //隨機(jī)數(shù)生成:根據(jù)角標(biāo)拿字符串的值 const randomNum = (min = 0, max: number) => Math.floor(Math.random() * (max - min)) + min;
組件化及可視化增強(qiáng)
下面我們來做一個(gè)完整的vue驗(yàn)證碼組件,并借助Canvas
添加干擾線和干擾點(diǎn)的效果。
既然是組件,就需要幾個(gè)參數(shù)供調(diào)用者調(diào)整,常規(guī)的就是組件的寬、高、字號以及是否需要干擾線或干擾點(diǎn),所以這里只定義了這幾個(gè)參數(shù)。
多余的就不說了,直接上代碼。
1、vue驗(yàn)證碼組件代碼:
<template> <div class="s-canvas"> <canvas id="s-canvas" :width="contentWidth" :height="contentHeight" @click="refreshCode" ></canvas> </div> </template> <script lang="ts" setup> import { ref, onMounted, withDefaults, defineProps } from "vue"; // 定義props類型 interface CodeProps { /** 默認(rèn)驗(yàn)證碼 */ defaultCode?: string; /** 容器寬度 */ contentWidth?: number; /** 容器高度 */ contentHeight?: number; /** 最大干擾線,0時(shí)無干擾線 */ maxLine?: number; /** 最大干擾點(diǎn),0時(shí)無干擾點(diǎn) */ maxDot?: number; /** 字體最小值 */ fontSizeMin?: number; /** 字體最大值 */ fontSizeMax?: number; } // props默認(rèn)值 const props = withDefaults(defineProps<CodeProps>(), { contentWidth: 90, contentHeight: 30, fontSizeMin: 25, fontSizeMax: 30, maxLine: 4, maxDot: 10, }); const emit = defineEmits(["update:verifyCode"]); //驗(yàn)證碼 const verifyCode = ref(""); onMounted(() => { verifyCode.value = props.defaultCode || makeCode(); emit("update:verifyCode", verifyCode.value); drawPic(verifyCode.value); }); // 生成校驗(yàn)碼 const makeCode = (len = 4) => { let code = ""; const codeLength = len; //驗(yàn)證碼的長度 // 定義生成驗(yàn)證碼的字符集,去除易混淆的字符集1il0oO const identifyCodes = "123456789abcdefjhijkinpqrsduvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; for (let i = 0; i < codeLength; i++) { // 獲取隨機(jī)字符 code += identifyCodes[randomNum(0, identifyCodes.length)]; } return code; //把code值賦給驗(yàn)證碼 }; // 重置驗(yàn)證碼 const refreshCode = () => { verifyCode.value = makeCode(); emit("update:verifyCode", verifyCode.value); drawPic(verifyCode.value); }; // 定義暴露接口 // defineExpose({ refreshCode }); //隨機(jī)數(shù)生成:根據(jù)角標(biāo)拿字符串的值 const randomNum = (min = 0, max: number) => Math.floor(Math.random() * (max - min)) + min; // 生成一個(gè)隨機(jī)的顏色 function randomColor(min: number, max: number) { let r = randomNum(min, max); let g = randomNum(min, max); let b = randomNum(min, max); return "rgb(" + r + "," + g + "," + b + ")"; } /** 繪制文字 */ function drawPic(verifyCode: string) { let canvas = document.getElementById("s-canvas") as HTMLCanvasElement; if (!canvas) { console.error("找不到 canvas 元素"); return; } //創(chuàng)建一個(gè)2D對象作為上下文。 let ctx = canvas.getContext("2d") as CanvasRenderingContext2D; ctx.textBaseline = "bottom"; // 繪制背景 ctx.fillStyle = "#e6ecfd"; ctx.fillRect(0, 0, props.contentWidth, props.contentHeight); // 繪制文字 for (let i = 0; i < verifyCode.length; i++) { drawText(ctx, verifyCode, i); } drawLine(ctx, props.maxLine); drawDot(ctx, props.maxDot); } /**在畫布上顯示數(shù)據(jù) * @param ctx CanvasRenderingContext2D * @param verifyCode 要顯示的文字 * @param index 字符索引 */ function drawText(ctx: CanvasRenderingContext2D, verifyCode: string, index: number) { ctx.fillStyle = randomColor(50, 160); // 隨機(jī)生成字體顏色 ctx.font = randomNum(props.fontSizeMin, props.fontSizeMax) + "px SimHei"; // 隨機(jī)生成字體大小 let x = (index + 1) * (props.contentWidth / (verifyCode.length + 1)); let y = randomNum(props.fontSizeMax, props.contentHeight - 5); var deg = randomNum(-10, 15); // 修改坐標(biāo)原點(diǎn)和旋轉(zhuǎn)角度 ctx.translate(x, y); ctx.rotate((deg * Math.PI) / 180); ctx.fillText(verifyCode[index], 0, 0); // 恢復(fù)坐標(biāo)原點(diǎn)和旋轉(zhuǎn)角度 ctx.rotate((-deg * Math.PI) / 180); ctx.translate(-x, -y); } /** 繪制干擾線 * @param ctx CanvasRenderingContext2D * @param max 最大干擾線個(gè)數(shù) */ function drawLine(ctx: CanvasRenderingContext2D, maxLine = 4) { if (maxLine <= 0) { return; } for (let i = 0; i < maxLine; i++) { ctx.strokeStyle = randomColor(150, 200); ctx.beginPath(); ctx.moveTo(randomNum(0, props.contentWidth), randomNum(0, props.contentHeight)); ctx.lineTo(randomNum(0, props.contentWidth), randomNum(0, props.contentHeight)); ctx.stroke(); } } /** 繪制干擾點(diǎn) * @param ctx CanvasRenderingContext2D * @param max 最大干擾點(diǎn)個(gè)數(shù) */ function drawDot(ctx: CanvasRenderingContext2D, maxDot = 10) { if (maxDot <= 0) { return; } for (let i = 0; i < maxDot; 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(); } } </script>
2、使用驗(yàn)證碼組件
代碼可直接復(fù)制進(jìn)行驗(yàn)證,ui使用了ant-design-vue,如果用的不是ant,則直接替換組件即可。
<template> <div class="main"> <div class="container"> <div> <a-input placeholder="請輸入驗(yàn)證碼" v-model:value="code"></a-input> </div> <div> <!--驗(yàn)證碼組件--> <VerifyCode v-model:verifyCode="identifyCode"></VerifyCode> </div> </div> <div> <p>當(dāng)前驗(yàn)證碼: {{ identifyCode }},手動輸入驗(yàn)證碼: {{ code }}</p> <a-button type="primary" @click="submit">提交</a-button> </div> </div> </template> <script lang="ts" setup> import { ref, onMounted } from "vue"; import { message } from "ant-design-vue"; import VerifyCode from "./verifyCode.vue"; // 驗(yàn)證碼輸入框內(nèi)容 let code = ref(""); // 驗(yàn)證碼圖片內(nèi)容 let identifyCode = ref(""); function submit() { if (code.value == "") { message.error("請先輸入驗(yàn)證碼"); return; } if (identifyCode.value == code.value) { message.success("驗(yàn)證碼正確?"); } else { message.error("驗(yàn)證碼錯(cuò)誤,請重新輸入!"); } } </script> <style lang="less" scoped> .main { padding: 20px; } .container { display: flex; flex-direction: row; align-items: flex-start; justify-content: center; } </style>
注意事項(xiàng):
- 通過
update:verifyCode:
來實(shí)現(xiàn)驗(yàn)證碼的自動回填,減少了業(yè)務(wù)使用方的數(shù)據(jù)交互處理。
最終效果
總結(jié)
到此這篇關(guān)于vue3純前端實(shí)現(xiàn)驗(yàn)證碼的文章就介紹到這了,更多相關(guān)vue3純前端驗(yàn)證碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue3?實(shí)現(xiàn)一個(gè)自定義toast?小彈窗功能
這篇文章主要介紹了Vue3?實(shí)現(xiàn)一個(gè)自定義toast?小彈窗,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09Vue.js實(shí)現(xiàn)數(shù)據(jù)雙向綁定的代碼示例
在我們使用vue的時(shí)候,當(dāng)數(shù)據(jù)發(fā)生了改變,界面也會跟著更新,但這并不是理所當(dāng)然的,我們修改數(shù)據(jù)的時(shí)候vue是如何監(jiān)聽數(shù)據(jù)的改變以及當(dāng)數(shù)據(jù)發(fā)生改變的時(shí)候vue如何讓界面刷新的,所以本文就給大家講講Vue.js 數(shù)據(jù)雙向綁定是如何實(shí)現(xiàn)的2023-07-07Vue項(xiàng)目報(bào)錯(cuò):Uncaught SyntaxError: Unexpected token <
這篇文章主要介紹了Vue項(xiàng)目報(bào)錯(cuò):Uncaught SyntaxError: Unexpected token <,在引入第三方依賴的 JS 文件時(shí),遇到的一個(gè)問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-11-11Vue實(shí)現(xiàn)父子組件傳值其實(shí)不難
這篇文章主要介紹了Vue實(shí)現(xiàn)父子組件傳值其實(shí)不難問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03vue for循環(huán)出來的數(shù)據(jù)實(shí)現(xiàn)用逗號隔開
HTML(HyperText Markup Language)是用于創(chuàng)建網(wǎng)頁的標(biāo)準(zhǔn)標(biāo)記語言,正確的HTML編碼和結(jié)構(gòu)對于網(wǎng)頁的正確顯示至關(guān)重要,當(dāng)HTML代碼正確無誤時(shí),網(wǎng)頁的效果圖將與設(shè)計(jì)師的預(yù)期相符,反之則可能出現(xiàn)布局錯(cuò)亂、樣式失效等問題2024-10-10Vue3+Canvas實(shí)現(xiàn)簡易的貪吃蛇游戲
貪吃蛇作為一個(gè)經(jīng)典的小游戲,是很多人兒時(shí)的記憶,當(dāng)時(shí)的掌機(jī)、諾基亞手機(jī)里面都有它的身影。本文將用Vue3?Canvas來復(fù)刻一下這款游戲,感興趣的可以了解一下2022-07-07