vue3中实现拖拽滑块功能

1,115 阅读1分钟

在vue3+vant的h5项目开发中,被产品经理要求在PC上实现拼图验证码登录的功能,无奈vant组件只支持touch事件,不支持鼠标的mousedown,mousemove,mouseup事件,只能自己写一个兼容mouse和touch事件的功能。


本着能省则省的原则,代码尽量少写,多余的功能一概不要,直接上代码

    <!-- 滑块 -->
     <img
        :style="{ left: delta + 'px' }"
        class="slide-pic-pc"
        :src="slide"
        alt=""
        @mousedown="startDrag"
        @touchstart="startDrag"
        @mousemove="onDrag"
        @touchmove="onDrag"
        @mouseup="stopDrag"
        @touchend="stopDrag"
      />
      <!--进度条 -->
      <div class="step-line">
        <div class="step-line-active" :style="{ width: delta + 'px' }"></div>
      </div>
<script lang="ts">
import { defineComponent, ref, watch, onMounted } from 'vue' 
// 省略若干代码
export default defineComponent({  
  setup() {
    const canvasW = ref() // 主图宽度 
    const blockOffsetX = ref(0) // 小图偏移量

    // 校验位置
    const validPosition = () => {...}
  
    // 兼容鼠标操作
    const start = ref(0)
    const end = ref(0)
    const isDragging = ref(false) // 是否正在拖动
    const delta = ref(0) // 偏移量
    // 开始拖拽
    const startDrag = (e: any) => {
      e.preventDefault() // 阻止默认操作 
      // 详见 MDN [event.preventDefault - Web API 接口参考 | MDN (mozilla.org)](https://developer.mozilla.org/zh-CN/docs/Web/API/Event/preventDefault)
      e = e.changedTouches ? e.changedTouches[0] : e // changedTouches为移动端的触摸属性,若没有则为pc端鼠标操作
      isDragging.value = true
      start.value = Math.round(e.clientX)
    }
    // 拖拽中
    const onDrag = (e: any) => {
      e.preventDefault()
      e = e.changedTouches ? e.changedTouches[0] : e
      if (
        isDragging.value &&
        e.clientX > start.value && // 控制滑动范围
        e.clientX < canvasW.value * 0.9 + start.value // 这里*0.9 是因为进度条的宽度为页面的90%
      ) {
        delta.value = Math.round(e.clientX) - start.value
      }
    }
    // 结束拖拽
    const stopDrag = (e: any) => {
      e.preventDefault()
      e = e.changedTouches ? e.changedTouches[0] : e
      isDragging.value = false
      end.value = Math.round(e.clientX)
      delta.value = Math.abs(start.value - end.value)
      validPosition() // 校验位置信息
    }

    watch(
      () => [delta.value],
      () => {
        blockOffsetX.value = delta.value
      },
      { immediate: true }
    )

    return {...}
  },
})
</script>