Vue移动端实现元素拖拽

  • 最近遇到一个需求,在App内嵌的H5页面上,有一个悬浮的客服图标,点击可跳转客服页面。最初这个客服图标采用的是固定定位的方式。现在新的需求是,可以拖拽该图标到屏幕任意位置,防止遮挡页面内容。
  • 思考实现的方式就是绑定touchstarttouchmovetouchend这三个事件(PC端对应的事件分别为mousedownmousemovemouseup),动态更新元素的位置,实现元素随手指(鼠标)移动。
  • 将逻辑处理封装成一个mixin,方便引用。处理好滑动穿透问题,防止页面随元素移动而滚动。

方法封装

/**
 * @name: draggable
 * @description: 元素拖拽
 */
const draggableMixin = {
  data () {
    return {
      // 元素位置,用于样式绑定,动态更新位置(:style="{left: `${x}px`, top: `${y}px`}")
      elePos: {
        x: null,
        y: null
      },
      // 手指(鼠标)触摸点[即拖拽开始的位置]距离拖拽元素左上角的距离
      diffOfTarget: {
        x: 0,
        y: 0
      }
    }
  },
  methods: {
    dragStartHandler (e) {
      let touch = e
      if (e.touches) {
        touch = e.touches[0]
      }
      this.diffOfTarget.x = touch.clientX - e.target.offsetLeft
      this.diffOfTarget.y = touch.clientY - e.target.offsetTop
      // 解决滑动穿透问题
      let scrollTop = document.scrollingElement.scrollTop
      console.log(scrollTop)
      // todo 在项目的全局样式下,需要定义一个modal-open的样式类
      /**
       * body.modal-open {
       *   position: fixed;
       *   width: 100%;
       *   min-height: 100%;
       * }
       */
      document.body.classList.add('modal-open')
      document.body.style.top = -scrollTop + 'px'
    },
    draggingHandler (e) {
      let touch = e
      if (e.touches) {
        touch = e.touches[0]
      }
      // 设置拖拽元素的位置
      this.elePos.x = touch.clientX - this.diffOfTarget.x
      this.elePos.y = touch.clientY - this.diffOfTarget.y
      // 限制元素不能超过屏幕
      if (this.elePos.x < 0) {
        this.elePos.x = 0
      } else if (this.elePos.x > window.screen.width) {
        this.elePos.x = window.screen.width - e.target.clientWidth
      }
      if (this.elePos.y < 0) {
        this.elePos.y = 0
      } else if (this.elePos.y > window.screen.height) {
        this.elePos.y = window.screen.height - e.target.clientHeight
      }
    },
    dragEndHandler (e) {
      document.body.classList.remove('modal-open')
    }
  }
}

export default draggableMixin


引用

<template>
  <div>
    <img
      src="../assets/img/customer-service.png"
      alt=""
      class="customer-service"
      :style="{'left': elePos.x + 'px', 'top': elePos.y + 'px' }"
      @mousedown="dragStartHandler"
      @touchstart.stop="dragStartHandler"
      @mousemove="draggingHandler"
      @touchmove.stop="draggingHandler"
      @mouseup="dragEndHandler"
      @touchend.stop="dragEndHandler"
    >
  </div>
</template>

<script>
  import draggableMixin from '@/mixins/draggable'
  export default {
    mixins: [ draggableMixin ]
  }
</script>

<style scoped>
.customer-service {
  position: fixed;
  left: 10px;
  top: 200px;
  width: 36px;
  height: 36px;
  cursor: pointer;
}
</style>
posted @ 2021-07-30 10:19  Tove丶  阅读(1297)  评论(0编辑  收藏  举报