实现效果
实现过程
校验
//密码格式校验
const validateUppercase = (rule, value, callback) => {
if (!/[A-Z]/.test(value)) {
callback(new Error('密码必须包含至少一个大写字母'));
} else {
callback();
}
};
const validateNumber = (rule, value, callback) => {
if (!/\d/.test(value)) {
callback(new Error('密码必须包含至少一个数字'));
} else {
callback();
}
};
const validateSpecialCharacter = (rule, value, callback) => {
if (!/[~`!@#$%^&*()_\-+={}[\]|;:,<>.?/]/.test(value)) {
callback(new Error('密码必须包含至少一个特殊字符'));
} else {
callback();
}
};
源代码?
<template>
<div class="registerform">
<h1>注册账户</h1>
<div class="registerWarp">
<el-form
label-position="top"
label-width="100px"
:model="form"
ref="ruleFormRef"
:rules="rulesForm"
hide-required-asterisk
class="register-form"
>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="电子邮箱" />
</el-form-item>
<el-form-item label="密码" prop="pwd">
<el-input
v-model="form.pwd"
type="password"
show-password
placeholder="登录密码"
@focus="showTooltip"
@blur="hideTooltip"
@input="handleInput"
/>
<!-tips提示->
<div class="pwdTips" v-show="isPwdShowTips">
<p>
<img
v-show="!isCheck1"
src="@/assets/images/register/check-0.svg"
/>
<img
v-show="isCheck1"
src="@/assets/images/register/check-1.svg"
/>
<span>6-24个字符</span>
</p>
<p>
<img
v-show="!isCheck2"
src="@/assets/images/register/check-0.svg"
/>
<img
v-show="isCheck2"
src="@/assets/images/register/check-1.svg"
/>
<span>至少一个大写字母</span>
</p>
<p>
<img
v-show="!isCheck3"
src="@/assets/images/register/check-0.svg"
/>
<img
v-show="isCheck3"
src="@/assets/images/register/check-1.svg"
/>
<span>至少一个数字</span>
</p>
<p>
<img
v-show="!isCheck4"
src="@/assets/images/register/check-0.svg"
/>
<img
v-show="isCheck4"
src="@/assets/images/register/check-1.svg"
/>
<span>至少一个特殊字符</span>
</p>
<p>特殊字符支持:~`!@#$%^&*()_-+={}[]|;:,<>.?/</p>
</div>
</el-form-item>
<el-form-item>
<template #label>
<div class="item-label">
<span>填写邀请ID(选填)</span>
<img
:class="{ active: isIdShow }"
@click="isIdShow = !isIdShow"
src="@/assets/images/register/right-jian.svg"
/>
</div>
</template>
<el-input
v-show="isIdShow"
v-model="form.parentShortId"
placeholder="填写邀请用户ID"
/>
</el-form-item>
<el-form-item>
<div class="form-bottom">
<div class="promise">
点击注册即表示同意<span>服务协议</span>和<span>隐私条款</span>
</div>
<div
class="submit-btn"
type="primary"
@click="submitForm(ruleFormRef)"
>
注册
</div>
<div class="switch-login">
已有账户?<span @click="goPath('/login')">去登录</span>
</div>
</div>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script setup>
import { ref, reactive, defineEmits, watch } from 'vue';
import { emailCodeSend } from '@/api/user';
import { EmailSceneTypeMap } from '@/views/Login/const.js';
import { debounce } from '@/utils';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
const router = useRouter();
const store = useStore();
const goPath = (r) => {
router.push({
path: r
});
};
const isIdShow = ref(false);
const ruleFormRef = ref(null);
const form = reactive({
email: '',
pwd: '',
code: '',
parentShortId: '',
captcha: '123456'
});
// 发送验证码
const getEmailCode = debounce(async (val) => {
try {
await store.dispatch('app/showLoading');
let params = {
scene: EmailSceneTypeMap['REGISTER'],
email: val,
captcha: '123456'
};
const { data } = await emailCodeSend(params);
console.log(data);
if (data.code == 'Success') {
store.dispatch(
'app/showToast',
{
msg: '验证码已发送',
type: 'success'
},
{ root: true }
);
emits('stepRouter', { step: 2, form });
return data.data.sec;
}
} catch (error) {
console.log('getEmailCode-Error', error);
} finally {
await store.dispatch('app/hideLoading');
}
}, 300);
// 密码提示
const isPwdShowTips = ref(false);
const showTooltip = () => {
console.log('showTooltip');
isPwdShowTips.value = true;
handleInput(form.pwd);
};
const hideTooltip = () => {
console.log('hideTooltip');
isPwdShowTips.value = false;
};
// 输入框校验
const isCheck1 = ref(false);
const isCheck2 = ref(false);
const isCheck3 = ref(false);
const isCheck4 = ref(false);
const handleInput = (value) => {
console.log('handleInput');
if (value.length < 6 || value.length > 24) {
isCheck1.value = false;
} else {
isCheck1.value = true;
}
if (!/[A-Z]/.test(value)) {
isCheck2.value = false;
} else {
isCheck2.value = true;
}
if (!/\d/.test(value)) {
isCheck3.value = false;
} else {
isCheck3.value = true;
}
if (!/[~`!@#$%^&*()_\-+={}[\]|;:,<>.?/]/.test(value)) {
isCheck4.value = false;
} else {
isCheck4.value = true;
}
};
//密码格式校验
const validateUppercase = (rule, value, callback) => {
if (!/[A-Z]/.test(value)) {
callback(new Error('密码必须包含至少一个大写字母'));
} else {
callback();
}
};
const validateNumber = (rule, value, callback) => {
if (!/\d/.test(value)) {
callback(new Error('密码必须包含至少一个数字'));
} else {
callback();
}
};
const validateSpecialCharacter = (rule, value, callback) => {
if (!/[~`!@#$%^&*()_\-+={}[\]|;:,<>.?/]/.test(value)) {
callback(new Error('密码必须包含至少一个特殊字符'));
} else {
callback();
}
};
const rulesForm = reactive({
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '邮箱输入格式错误', trigger: 'blur' }
],
pwd: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 24, message: '密码长度为6-24个字符', trigger: 'blur' },
{ validator: validateUppercase, trigger: 'blur' },
{ validator: validateNumber, trigger: 'blur' },
{ validator: validateSpecialCharacter, trigger: 'blur' }
]
});
const emits = defineEmits(['stepRouter']);
const submitForm = (formEl) => {
if (!formEl) return;
formEl.validate((valid) => {
if (valid) {
console.log('submit!');
getEmailCode(form.email);
// emits('stepRouter', { step: 2, form });
} else {
console.log('error submit!');
return false;
}
});
};
</script>
<style lang="less" scoped>
.registerform {
h1 {
color: #000;
font-family: PingFang SC;
font-size: 40px;
font-style: normal;
font-weight: 600;
line-height: normal;
margin-bottom: 40px;
}
.registerWarp {
.register-form {
//提示
.pwdTips {
position: absolute;
top: 51px;
width: 480px;
min-height: 210px;
flex-shrink: 0;
background-color: #fff;
z-index: 1;
border-radius: 5px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.15);
padding: 20px;
p {
display: flex;
align-items: center;
color: #000;
font-family: PingFang SC;
font-size: 14px;
font-weight: 400;
padding-bottom: 10px;
img {
margin-right: 11px;
}
&:last-child {
color: #909090;
font-family: PingFang SC;
font-size: 12px;
font-weight: 500;
padding-bottom: 0;
}
}
}
&.el-form {
:deep(.el-form-item__label) {
color: #000;
font-family: PingFang SC;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
margin-bottom: 0;
}
.el-form-item {
position: relative;
margin-top: 20px;
.form-bottom {
.promise {
color: #000;
font-family: PingFang SC;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
span {
color: #3183ff;
}
}
.submit-btn {
width: 480px;
height: 48px;
border-radius: 40px;
background: #090909;
color: #fff;
font-family: PingFang SC;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
margin-bottom: 30px;
user-select: none;
cursor: pointer;
}
.switch-login {
color: #000;
font-family: PingFang SC;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
text-align: center;
span {
color: #3183ff;
cursor: pointer;
}
}
}
.item-label {
display: flex;
justify-content: space-between;
img {
width: 11px;
height: 11px;
transform: rotate(90deg);
transition: transform 0.3s ease;
cursor: pointer;
&.active {
transform: rotate(270deg);
}
}
}
.el-input {
width: 480px;
height: 40px;
background: #ffffff;
margin-top: 10px;
border: 1px solid #ebebeb;
border-radius: 4px;
::placeholder {
font-size: 14px;
line-height: 20px;
color: #c8c8c8;
}
}
:deep(.el-input__inner) {
color: #000;
}
}
}
}
}
}
</style>