基于vue-drag-verify二次开发滑块滑动验证
本文介绍了基于vue-drag-verify二次开发的滑块验证组件实现。在父组件login.vue中,通过引用CustomDragVerify子组件实现滑块验证功能,并处理验证成功/失败回调。子组件CustomDragVerify.vue扩展了原生组件功能,通过精细控制鼠标事件实现严格的滑块状态管理,包括位置计算、进度条显示和验证状态判断。关键点包括:1) 通过鼠标移动事件实时计算滑块位置;2)
·
基于vue-drag-verify二次开发登录滑块滑动验证
vue-drag-verify组件的滑块验证需要鼠标在滑块框内滑动才判定有效。
这个组件功能是点击滑块按下鼠标后,哪怕鼠标移到滑块框外,在屏幕中滑动,滑块也能跟随滑动。
父组件 login.vue
<template>
<div class="login">
<custom-drag-verify
class="dragVerifybox"
ref="customDragVerify"
handlerIcon="el-icon-d-arrow-right"
successIcon="el-icon-circle-check"
@fail="onDragFail"
@success="onDragSuccess"
@passcallback="onDragSuccess"
style="margin-bottom: 10px"
/>
</div>
</template>
<script>
import CustomDragVerify from "@/components/dragVerify/CustomDragVerify";
export default {
name: "Login",
components: { CustomDragVerify },
data() {
return {
sliderSuccess: false,
};
},
methods: {
//登录按钮验证
handleLogin() {
this.$refs.loginForm.validate((valid) => {
if (valid) {
if (!this.sliderSuccess) {
this.$message.error("请拖动滑块完成验证");
return;
}
});
},
// 验证通过
onDragSuccess() {
this.sliderSuccess = true;
},
// 验证失败
onDragFail() {
this.sliderSuccess = false;
},
子组件 CustomDragVerify.vue
<template>
<drag-verify
ref="dragVerify"
:width="width"
:height="height"
:text="text"
:success-text="successText"
:background="background"
:progress-bar-bg="progressBarBg"
:completed-bg="completedBg"
:handler-bg="handlerBg"
:handler-icon="currentIcon"
:text-size="textSize"
:success-icon="successIcon"
:circle="circle"
@fail="$emit('fail')"
@success="$emit('success')"
@mousedown.native="handleMouseDown"
/>
</template>
<script>
import DragVerify from 'vue-drag-verify';
export default {
components: { DragVerify },
props: {
width: { type: Number, default: 300 },
height: { type: Number, default: 50 },
text: { type: String, default: '请按住滑块拖动' },
successText: { type: String, default: '验证通过' },
background: { type: String, default: '#e8e8e8' },
progressBarBg: { type: String, default: '#76c61d' },
completedBg: { type: String, default: '#76c61d' },
handlerBg: { type: String, default: '#fff' },
handlerIcon: { type: String, default: 'el-icon-arrow-right' },
textSize: { type: String, default: '14px' },
successIcon: { type: String, default: 'el-icon-success' },
circle: { type: Boolean, default: false }
},
data() {
return {
currentIcon: this.handlerIcon,
isVerified: false,
};
},
mounted() {
},
methods: {
handleMouseDown() {
if (this.isVerified) return;
const handler = this.$refs.dragVerify.$el.querySelector('.dv_handler');
const container = this.$refs.dragVerify.$el;
const dragInstance = this.$refs.dragVerify;
// 判断是否点击在滑块上
const rect = container.getBoundingClientRect();
const eventX = event.clientX;
const eventY = event.clientY;
const handlerRect = handler.getBoundingClientRect();
// 是否真正按住了滑块
const isPressedOnHandler =
eventX >= handlerRect.left &&
eventX <= handlerRect.right &&
eventY >= handlerRect.top &&
eventY <= handlerRect.bottom;
// 如果没按住滑块,直接返回,不触发拖动
if (!isPressedOnHandler) return;
// 初始化组件状态
dragInstance.isDragging = true;
dragInstance.isMoving = false;
dragInstance.isCompleted = false;
dragInstance.isPassing = false;
let isMouseInContainer = true;
const onMouseEnter = () => {
isMouseInContainer = true;
};
const onMouseMove = (e) => {
const rect = container.getBoundingClientRect();
isMouseInContainer = (
e.clientX >= rect.left &&
e.clientX <= rect.right &&
e.clientY >= rect.top &&
e.clientY <= rect.bottom
);
// 严格状态控制
if (!handler || !dragInstance.isDragging || !dragInstance.isMoving) return;
const left = Math.max(0, Math.min(e.clientX - rect.left, rect.width - handler.offsetWidth));
handler.style.left = `${left}px`;
dragInstance.sliderPosition = left;
// 实时检测是否到达末端
const isAtEnd = left >= rect.width - handler.offsetWidth - 1;
if (isAtEnd) {
dragInstance.sliderPosition = rect.width - handler.offsetWidth;
}
// 进度条
const progressBar = container.querySelector('.dv_progress_bar');
if (progressBar) {
progressBar.style.width = `${left}px`;
}
};
const onMouseUp = (e) => {
const rect = container.getBoundingClientRect();
isMouseInContainer = (
e.clientX >= rect.left &&
e.clientX <= rect.right &&
e.clientY >= rect.top &&
e.clientY <= rect.bottom
);
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
container.removeEventListener('mouseenter', onMouseEnter);
// 滑块位置兜底判断
const handlerLeft = parseFloat(handler.style.left) || 0;
const isAtEnd = handlerLeft >= rect.width - handler.offsetWidth - 1;
if (isPressedOnHandler && isAtEnd) {
// 验证成功逻辑 - 保持滑块位置并应用成功样式
handler.style.left = `${rect.width - handler.offsetWidth}px`;
dragInstance.sliderPosition = rect.width - handler.offsetWidth;
// 进度条100%
const progressBar = container.querySelector('.dv_progress_bar');
if (progressBar) {
progressBar.style.width = '100%';
}
dragInstance.isDragging = false;
dragInstance.isMoving = false;
dragInstance.isCompleted = true;
dragInstance.isPassing = true;
this.isVerified = true;
this.currentIcon = this.successIcon;
dragInstance.$emit('success');
}
else {
// 验证失败
handler.style.left = '0px';
dragInstance.sliderPosition = 0;
const progressBar = container.querySelector('.dv_progress_bar');
if (progressBar) {
progressBar.style.width = '0px';
}
dragInstance.isDragging = false;
dragInstance.isMoving = false;
dragInstance.isCompleted = false;
dragInstance.isPassing = false;
this.currentIcon = this.handlerIcon;
// 触发失败事件
dragInstance.$emit('fail');
}
};
// 绑定新事件
container.addEventListener('mouseenter', onMouseEnter);
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
// 设置组件状态
dragInstance.isMoving = true;
}
}
};
</script>
登录前滑块状态

登录后滑块状态
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)