功能
模拟了纯前端的邮箱登录逻辑
还没有连接后端的发送邮件的服务
后续计划,再做一个邮箱、密码登录的界面
然后把这两个一块连接上后端
技术介绍
主要介绍绘制图形人机验证乃个
使用的是canvas,在源码里就有
界面控制主要就是用 表格、表单(其实表单都没怎么用到)、v-if、文本输入框和按钮。
效果图
代码
Auth.vue
<template><div><form @submit.prevent="handleSubmit"><table><!-- 邮箱输入框 --><tr v-show="!showEmailVerification"><td><label for="email">邮箱</label></td><td colspan="2"><input type="email" id="email" v-model="formData.email" placeholder="请输入邮箱" required></td></tr><!-- 人机校验 --><tr v-show="!showEmailVerification"><td><button type="button" @click="refreshCaptcha"><canvas ref="myCanvas" width="90" height="25"></canvas></button></td><td><input type="text" id="captcha" v-model="userInputCaptchaText" placeholder="请输入验证码" required></td></tr><tr v-show="!showEmailVerification"><td></td><td><button type="button" @click="sendEmail">人机验证</button></td></tr><!-- 邮箱认证 --><tr v-show="showEmailVerification"><td><label for="emailVerificationCode">验证码</label></td><td colspan="2"><input type="text" id="emailVerificationCode" v-model="formData.emailVerificationCode" placeholder="请输入邮箱验证码" required></td></tr><tr v-show="showEmailVerification"><td></td><td colspan="2"><button type="button" @click="verifyEmailVerificationCode">提交验证码</button></td></tr><!-- 消息通知栏 --><tr><td colspan="2">{{ message }}</td></tr></table></form></div>
</template><script setup>
import { onMounted } from 'vue';
import useFormValidation from './formValidation';const {formData,userInputCaptchaText,showEmailVerification,message,refreshCaptcha,sendEmail,verifyEmailVerificationCode,
} = useFormValidation();// Initialize captcha on component mount
onMounted(refreshCaptcha);function handleSubmit() {// 可以在这里添加表单提交逻辑
}
</script><style scoped>
table, th, td {border: 1px solid black;border-collapse: collapse;
}
</style>
captcha.js
export function drawCaptcha(ctx, width, height) {// 填充背景色ctx.fillStyle = '#f2f2f2';ctx.fillRect(0, 0, width, height);// 设置字符集const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789';const charCount = 4; // 验证码字符数let captchaText = '';// 随机生成验证码文本for (let i = 0; i < charCount; i++) {captchaText += chars.charAt(Math.floor(Math.random() * chars.length));}// 设置字体样式ctx.font = '24px Arial';ctx.fillStyle = '#333';ctx.textBaseline = 'middle';// 绘制字符for (let i = 0; i < captchaText.length; i++) {const x = i * 24;const y = height / 2;const angle = (Math.random() - 0.5) * 0.6; // 随机旋转角度ctx.save();ctx.translate(x, y);ctx.rotate(angle);ctx.fillText(captchaText.charAt(i), 0, 0);ctx.restore();}// 添加干扰线条for (let i = 0; i < 10; i++) {ctx.strokeStyle = getRandomColor();ctx.beginPath();ctx.moveTo(Math.random() * width, Math.random() * height);ctx.lineTo(Math.random() * width, Math.random() * height);ctx.stroke();}// 添加噪点for (let i = 0; i < 50; i++) {ctx.fillStyle = getRandomColor();ctx.beginPath();ctx.arc(Math.random() * width, Math.random() * height, 1, 0, Math.PI * 2);ctx.fill();}return captchaText;
}function getRandomColor() {const r = Math.floor(Math.random() * 256);const g = Math.floor(Math.random() * 256);const b = Math.floor(Math.random() * 256);return `rgb(${r},${g},${b})`;
}
formValidation.js
import { ref } from 'vue';
import { drawCaptcha } from './captcha';
import axios from 'axios';export default function useFormValidation() {const formData = ref({email: '',emailVerificationCode: ''});const userInputCaptchaText = ref('');let captchaText = '';const isValid = ref(false);const showEmailVerification = ref(false);const loginSuccess = ref(false);const message = ref('');function refreshCaptcha() {const canvas = document.querySelector('canvas');const ctx = canvas.getContext('2d');captchaText = drawCaptcha(ctx, canvas.width, canvas.height);}function sendEmail() {if (!isValidEmail(formData.value.email)) {message.value = '请输入有效的邮箱地址';return;}if (isValidCaptcha(userInputCaptchaText.value, captchaText)) {isValid.value = true;showEmailVerification.value = true;message.value = '请查收邮箱验证码';// 发送邮件验证码的逻辑可以放在这里sendVerificationCode(formData.value.email);} else {message.value = '验证码错误,请重新输入';refreshCaptcha();userInputCaptchaText.value = '';isValid.value = false;showEmailVerification.value = false;}}const sendVerificationCode = async (email) => {try {const response = await axios.post('http://localhost:8080/api/register', { email }, {headers: {'Content-Type': 'application/json'}});console.log('Verification code sent successfully:', response.data);} catch (error) {console.error('Error sending verification code:', error);}};// 校验邮箱验证码function verifyEmailVerificationCode() {if (isValidEmailVerificationCode(formData.value.emailVerificationCode)) {loginSuccess.value = true;message.value = '邮箱验证码校验通过,登录成功!';} else {message.value = '邮箱验证码错误,请重新输入';}}const isValidEmailVerificationCode = async (code) => {console.log(code);try {const response = await axios.post('http://localhost:8080/api/checkEmail', { code }, {headers: {'Content-Type': 'application/json'}});console.log('Verification code check result:', response.data);return response.data;} catch (error) {console.error('Error checking verification code:', error);message.value = '校验邮箱验证码时发生错误';return false;}}return {formData,userInputCaptchaText,isValid,showEmailVerification,loginSuccess,message,refreshCaptcha,sendEmail,verifyEmailVerificationCode};
}function isValidEmail(email) {const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;return emailRegex.test(email);
}function isValidCaptcha(inputCaptcha, generatedCaptcha) {return inputCaptcha.toLowerCase() === generatedCaptcha.toLowerCase();
}