Vue基于ElementUI组件实现滑块登录验证组件
Posted 北溟溟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue基于ElementUI组件实现滑块登录验证组件相关的知识,希望对你有一定的参考价值。
引言
在实际项目应用开发中,为了防止用户频繁发起登录请求,导致后端登录访问压力瞬时过大,我们可以设计一些验证规则防刷,最常见的方式是通过输入验证码的方式降低刷新频率,后台通过返回不同的验证码从而降低用户的频繁请求,这里我们提供一种前端的方式,降低防刷的频率,那就是滑块验证码验证。话不多说,先上效果图。
本组件的集成及案例教程依然在我们的ATP应用测试平台中,源码地址:https://gitee.com/northcangap/atp.git,仅供参考。滑块组件使用vue+element实现,希望你对vue中的常用功能有所了解,关于父子组件传值,watch、computed等监控的了解。
正文
- 创建滑块验证组件slider-verify-code.vue
<template>
<div class="drag" :style="style">
<div class="background"/>
<div class="text shadow" onselectstart="return false" :style="{ color: textColor }">
<slot name="content">
{{ content }}
</slot>
</div>
<div class="slider" :style="{height,width:sliderWidth}">
<slot v-if="icon" name="icon">
<i :class="icon"></i>
</slot>
<slot v-else name="icon">
>>
</slot>
</div>
</div>
</template>
<script>
const debounce = (function () {
let timer = 0
return function (callback, ms) {
clearTimeout(timer)
timer = setTimeout(callback, ms)
}
})();
export default {
name: 'slider-verify-code',
model: {
event: 'change',
prop: 'isLock'
},
props: {
isLock: { //解锁状态
type: [String, Boolean, Number, Object],
required: true,
default: false
},
icon: { //滑块图标
type: [String],
default: "el-icon-d-arrow-right"
},
activeValue: { //滑块解锁后的值
type: [String, Boolean, Number, Object],
default: true
},
inactiveValue: { //滑块解锁前的值
type: [String, Boolean, Number, Object],
default: false
},
content: { //滑块的文字
type: [String],
default: "请向右拖动滑块"
},
height: { //高度
type: [String],
default: "40px"
},
sliderWidth: { //滑块宽度
type: [String],
default: "40px"
},
background: { //高度
type: [String],
default: "#e8e8e8"
},
textColor: { //滑块的文字颜色
type: [String],
default: "#777"
}
},
watch: {
isLock(data) { //重置样式
!data && this.init();
},
},
computed: {
style() {
const {height, background} = this;
return {height, 'line-height': height, background};
},
resize() {
return document.body.clientWidth;
},
},
mounted() {
this.init();
window.onresize = () => {
debounce(() => {
this.init();
}, 120);
};
},
methods: {
/**
* 定义一个获取DOM元素的方法-选择器
*/
selector(selector) {
return document.querySelector(selector);
},
/**
* 初始化
*/
init() {
const box = this.selector('.drag'); //容器
const background = this.selector('.background'); //背景
const text = this.selector('.text'); //文字
const slider = this.selector('.slider');//滑块
const distance = box.offsetWidth - slider.offsetWidth;//滑动成功的宽度(距离)
let success = this.inactiveValue;//是否通过验证的标志
// 初始化的时候 清除所有属性
slider.style.transition = null;
background.style.transition = null;
slider.style.left = 0 + 'px';
background.style.width = 0 + 'px';
text.innerhtml = this.content;
slider.innerHTML = '<i class="el-icon-d-arrow-right"></i>';
slider.style.color = '#777';
//二、给滑块注册鼠标按下事件
slider.onmousedown = (event) => {
//1.鼠标按下之前必须清除掉后面设置的过渡属性
slider.style.transition = null;
background.style.transition = null;
//说明:clientX 事件属性会返回当事件被触发时,鼠标指针向对于浏览器页面(或客户区)的水平坐标。
//2.当滑块位于初始位置时,得到鼠标按下时的水平位置
const ev = event || window.event;
const downX = ev.clientX;
//三、给文档注册鼠标移动事件
document.onmousemove = (e) => {
const evt = e || window.event;//是为了更好的兼容IE浏览器和非ie浏览器。在ie浏览器中,window.event是全局变量,在非ie中,就需要自己传入一个参数来获取event啦,所以就有了var e = e||window.event
//1.获取鼠标移动后的水平位置
const moveX = evt.clientX;
//2.得到鼠标水平位置的偏移量(鼠标移动时的位置 - 鼠标按下时的位置)
let offsetX = moveX - downX;
//3.在这里判断一下:鼠标水平移动的距离 与 滑动成功的距离 之间的关系
if (offsetX > distance) {
offsetX = distance;//如果滑过了终点,就将它停留在终点位置
} else if (offsetX < 0) {
offsetX = 0;//如果滑到了起点的左侧,就将它重置为起点位置
}
//4.根据鼠标移动的距离来动态设置滑块的偏移量和背景颜色的宽度
slider.style.left = offsetX + 'px';
background.style.width = offsetX + 'px';
//如果鼠标的水平移动距离 = 滑动成功的宽度
if (offsetX == distance) {
//1.设置滑动成功后的样式
text.innerHTML = '验证成功';
text.style.color = '#fff';
slider.innerHTML = '<i class="el-icon-success"></i>';
slider.style.color = '#53C300';
//2.设置滑动成功后的状态
success = this.activeValue;
//成功后,清除掉鼠标按下事件和移动事件(因为移动时并不会涉及到鼠标松开事件)
slider.onmousedown = null;
document.onmousemove = null;
//3.成功解锁后的回调函数
setTimeout(() => {
this.$emit('change', this.activeValue);
}, 100);
}
};
//四、给文档注册鼠标松开事件
document.onmouseup = () => {
//如果鼠标松开时,滑到了终点,则验证通过
if (success == this.activeValue) return true;
//反之,则将滑块复位(设置了1s的属性过渡效果)
slider.style.left = 0;
background.style.width = 0;
slider.style.transition = 'left 1s ease';
background.style.transition = 'width 1s ease';
//只要鼠标松开了,说明此时不需要拖动滑块了,那么就清除鼠标移动和松开事件。
document.onmousemove = null;
document.onmouseup = null;
};
};
/* 移动端 */
//二、给滑块注册鼠标按下事件
slider.ontouchstart = (event) => {
const touch = event.changedTouches[0];
//1.鼠标按下之前必须清除掉后面设置的过渡属性
slider.style.transition = null;
background.style.transition = null;
//说明:clientX 事件属性会返回当事件被触发时,鼠标指针向对于浏览器页面(或客户区)的水平坐标。
//2.当滑块位于初始位置时,得到鼠标按下时的水平位置
const downX = touch.pageX;
//三、给文档注册鼠标移动事件
document.ontouchmove = (e) => {
const tev = e.changedTouches[0];
//1.获取鼠标移动后的水平位置
const moveX = tev.pageX;
//2.得到鼠标水平位置的偏移量(鼠标移动时的位置 - 鼠标按下时的位置)
let offsetX = moveX - downX;
//3.在这里判断一下:鼠标水平移动的距离 与 滑动成功的距离 之间的关系
if (offsetX > distance) {
offsetX = distance;//如果滑过了终点,就将它停留在终点位置
} else if (offsetX < 0) {
offsetX = 0;//如果滑到了起点的左侧,就将它重置为起点位置
}
//4.根据鼠标移动的距离来动态设置滑块的偏移量和背景颜色的宽度
slider.style.left = offsetX + 'px';
background.style.width = offsetX + 'px';
//如果鼠标的水平移动距离 = 滑动成功的宽度
if (offsetX == distance) {
//1.设置滑动成功后的样式
text.innerHTML = '验证成功';
text.style.color = '#fff';
slider.innerHTML = '√';
slider.style.color = '#53C300';
//2.设置滑动成功后的状态
success = this.activeValue;
//成功后,清除掉鼠标按下事件和移动事件(因为移动时并不会涉及到鼠标松开事件)
slider.ontouchstart = null;
document.ontouchmove = null;
//3.成功解锁后的回调函数
setTimeout(() => {
this.$emit('change', this.activeValue);
// console.log('解锁成功');
}, 100);
}
};
//四、给文档注册鼠标松开事件
document.ontouchend = () => {
//如果鼠标松开时,滑到了终点,则验证通过
if (success == this.activeValue) return true;
//反之,则将滑块复位(设置了1s的属性过渡效果)
slider.style.left = 0;
background.style.width = 0;
slider.style.transition = 'left 1s ease';
background.style.transition = 'width 1s ease';
//只要鼠标松开了,说明此时不需要拖动滑块了,那么就清除鼠标移动和松开事件。
document.ontouchmove = null;
document.ontouchend = null;
};
};
}
}
};
</script>
<style scoped lang="scss">
* {
margin: 0px;
padding: 0px;
font-family: "微软雅黑";
box-sizing: border-box;
}
.drag {
height: 2.5rem;
line-height: 2.5rem;
background-color: #e8e8e8;
position: relative;
margin: 0 auto;
border-radius: 3px;
}
.background {
width: 2.5rem;
height: 100%;
position: absolute;
background-color: #53C300;
border-radius: 3px 0 0 3px;
}
.text {
position: absolute;
width: 100%;
height: 100%;
text-align: center;
user-select: none;
}
.slider {
width: 2.5rem;
height: 2.375rem;
position: absolute;
border: 1px solid #ccc;
cursor: move;
font-family: "宋体";
text-align: center;
background-color: #fff;
user-select: none;
color: #666;
}
.shadow {
text-align: center;
background: -webkit-gradient(linear, left top, right top, color-stop(0, #4d4d4d), color-stop(.2, #5d5d5d),
color-stop(.4, #6d6d6d), color-stop(.5, white), color-stop(.6, #6d6d6d), color-stop(.8, #5d5d5d), color-stop(1, #4d4d4d));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
-webkit-animation: animate 3s infinite;
}
@-webkit-keyframes animate {
from {
background-position: -80px;
}
to {
background-position: 80px;
}
}
@keyframes animate {
from {
background-position: -80px;
}
to {
background-position: 80px;
}
}
</style>
- 在登录页面集成登录滑块组件功能login.vue
<template>
<div class="container">
<el-form ref="form" :model="form" :rules="rules" label-width="70px" class="login">
<h3>ATP应用测试平台</h3>
<el-form-item label="用户名" prop="name">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="密码" prop="pass">
<el-input v-model="form.pass" type="password" show-password></el-input>
</el-form-item>
<el-form-item label="验证" prop="isLock">
<slider-verify-code v-model="form.isLock" @change="handlerLock"></slider-verify-code>
</el-form-item>
<el-button type="primary" @click="login" style="width: 100%;margin: 0;">立即登录</el-button>
</el-form>
</div>
</template>
<script>
import sliderVerifyCode from '@/components/slider-verify-code.vue';
export default {
name: "Login",
data() {
const checkStatus = (rule, value, callback) => {
if (!value) {
return callback(new Error("请拖动滑块完成验证"));
} else {
if (this.form.name == '' || this.form.pass == ''
|| !this.form.name || !this.form.pass) {
setTimeout(() => {
this.form.isLock = false;
this.$refs.form.validateField('name');
this.$refs.form.validateField('pass');
return callback(new Error("验证未通过"));
}, 1);
}
callback();
}
};
return {
form: {},
rules: {
name: [
{required: true, message: '用户名称不得为空!', trigger: 'blur'},
{min: 6, max: 18, message: '长度在 6 到 18 个字符', trigger: 'blur'}
],
pass: [
{required: true, message: '密码不得为空!', trigger: 'blur'},
{min: 6, max: 18, message: '长度在 6 到 18 个字符', trigger: 'blur'}
],
isLock: [
{validator: checkStatus, trigger: 'blur'},
],
},
}
},
components: {
'slider-verify-code': sliderVerifyCode
},
methods: {
//登录
login() {
this.$refs.form.validate((valid) => {
if (valid) {
this.$http.post('/sys/user/login', this.$qs.stringify(this.form)).then(res => {
if (res.data.code === 1) {
this.$router.push('/home')
} else {
this.$refs.form.resetFields();
this.$message.warning(res.data.msg);
}
}).catch(error => {
this.$message.error(error);
});
} else {
return false;
}
});
},
handlerLock(data) {
if (data) {
this.$refs.form.validateField('isLock');
}
},
}
}
</script>
<style scoped lang="scss">
.container {
width: 100%;
height: 100%;
overflow: auto;
background: rgb(84, 92, 100);
.login {
text-align: center;
padding: 20px 30px 30px 30px;
margin: 10% auto;
width: 320px;
background: white;
border-radius: 10px;
h3 {
margin: 30px 0px;
}
.el-form-item {
margin-bottom: 35px;
}
}
}
</style>
- 验证
结语
ok,关于Vue基于ElementUI组件实现滑块登录验证组件的介绍就到这里了,我们下期见。。。
以上是关于Vue基于ElementUI组件实现滑块登录验证组件的主要内容,如果未能解决你的问题,请参考以下文章