基于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>

登录前滑块状态

登录前滑块状态

登录后滑块状态
此为登录后滑块状态

Logo

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

更多推荐