<template>
<div class="login" @keyup.enter="clickLogin">
<div class="loginModule" ref="formWrap">
<div class="logo">
<img src="@/assets/images/logo.png" alt="" />
</div>
<div class="form">
<el-form ref="loginFormRef" :rules="loginRules" :model="loginForm">
<el-form-item prop="username">
<el-input
clearable
placeholder="用户名"
v-model="loginForm.username"
>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
clearable
show-password
placeholder="密码"
v-model="loginForm.password"
>
</el-input>
</el-form-item>
<div class="sliderValidate">
<div
class="validateWrap"
ref="sliderWrap"
:class="{
validatePass: validPass
}"
>
<div class="block" ref="slider">
<img
v-show="validPass"
src="@/assets/images/Login/slider-icon.png"
alt="滑块"
/>
<div class="sliderIcon" v-show="!validPass">
<DArrowRight style="width: 1em; height: 1em; " />
</div>
</div>
<span v-show="validPass" class="validatePass">验证通过</span>
<span v-show="!validPass" class="noValidate">拖动滑块校验</span>
</div>
</div>
<div class="showResetPassword">
<p>
<span class="sliderValid" v-if="showSliderWarn">请拖动滑块完成校验</span>
</p>
</div>
</el-form>
<a-button class="loginButton" type="primary" @click="clickLogin">登录</a-button>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
// ref:用于声明基础类型响应式数据, reactive:用于声明复杂类型响应式数据。unref:如果参数是一个 ref 则返回它的 value,否则返回参数本身
import {
reactive, ref, unref, onMounted, inject, getCurrentInstance } from "vue";
// 接口
import {
login } from "@/api/User";
// 节流
import throttle from "@/utils/common"
// 提示信息
const Mes: any = inject('$message')
// 登陆密码加密
import {
submitEncrypt } from '@/utils/jsencrypt';
// 对用户和密码进行类型限制
interface loginData {
username: string;
password: string;
}
//登录数据
let loginForm = reactive<loginData>({
username: "",
password: ""
});
// 检查用户名是否存在
const usernameCheck = async (rule: any, value: string, cb: any) => {
if (!/^\w{5,20}$/g.test(value)) {
return cb("用户名不合法");
}
};
// 登录数据校验
let loginRules = reactive({
username: [ {
required: true, message: "请输入用户名", trigger: "blur" }, {
validator: usernameCheck, trigger: 'blur' } ],
password: [ {
required: true, message: "请输入密码", trigger: "blur" } ]
});
// 表单校验结果
const loginFormRef = ref();
// 标示滑块校验是否通过
const validPass = ref(false)
// 显示滑块校验文字提示
const showSliderWarn = ref(false)
// 滑块 ref
const slider = ref()
// 滑块容器 ref
const sliderWrap = ref()
// 登陆模块 ref
const formWrap = ref()
/**
* 为滑块添加事件
*/
function sliderEvent() {
if (!slider.value || !sliderWrap.value) return null;
// 滑块容器的宽度
const sliderBoxWidth = sliderWrap.value.clientWidth;
// 滑块宽度
const sliderWidth = slider.value.clientWidth;
// 最大可拖动距离
const maxSlideX = sliderBoxWidth - sliderWidth;
// 滑块容器距离屏幕左边的距离(通过父级元素的offsetLeft计算)
const formClientX = formWrap.value.offsetLeft + 43;
// 滑块划过的过程
slider.value.onmousedown = function(e: any) {
const offsetX = e.offsetX
// 滑块校验已通过
if (validPass.value) {
return
}
// 鼠标在页面上进行移动
document.onmousemove = function(e: any) {
if (validPass.value) {
document.onmousemove = null;
document.onmouseup = null;
return;
}
const x = e.clientX - formClientX - offsetX;
if (x > 0 && x < maxSlideX) {
slider.value.style.left = x + "px";
}
if (x < 0) {
slider.value.style.left = "0px";
}
if (x > maxSlideX) {
slider.value.style.left = maxSlideX + "px";
validPass.value = true;
showSliderWarn.value = false;
}
if (x === maxSlideX) {
validPass.value = true;
showSliderWarn.value = false;
}
}
//鼠标按键被松开
document.onmouseup = function(e: any) {
const centerX = sliderBoxWidth / 2 - 23;
let x = e.clientX - formClientX - offsetX;
let timer: any = null;
// 恢复到起始点
if (x <= centerX && x > 0) {
timer = setInterval(() => {
x -= 2;
if (x <= 0) {
clearInterval(timer);
slider.value.style.left = "0px";
}
slider.value.style.left = x + "px";
}, 1);
} else if (x > centerX && x < maxSlideX) {
// 终点
timer = setInterval(() => {
x += 2;
if (x >= maxSlideX) {
clearInterval(timer);
slider.value.style.left = maxSlideX + "px";
validPass.value = true;
showSliderWarn.value = false;
}
slider.value.style.left = x + "px";
}, 1);
}
document.onmousemove = null;
document.onmouseup = null;
}
}
}
// 节流
const throttles = throttle(2000);
/**
* 登陆
*/
const clickLogin = () => {
throttles(async () => {
const form: any = unref(loginFormRef)
await form.validate()
if (validPass.value) {
showSliderWarn.value = false;
// 登陆
await isLogin();
} else {
showSliderWarn.value = true;
}
})
}
/**
* 执行登陆
*/
async function isLogin() {
try {
const {
data } = await login({
username: loginForm.username,
password: submitEncrypt(loginForm.password)
})
if (data.code) {
//登陆成功
}else{
// 失败
}
} catch (err) {
console.log('e', err)
Mes.error('用户名或密码错误,请重试')
}
}
onMounted(() => {
// ref页面组件还没有挂载完成,需要在挂载完成之后才能使用refs
sliderEvent()
});
</script>
<style lang="scss" scoped src="./Login.scss"></style>
转载:https://blog.csdn.net/weixin_44996782/article/details/127751280
查看评论