1. 程式人生 > >Vue拖拽組件

Vue拖拽組件

clientx chm false tex 引入 復用 wrap fff 跟著

vue開發公眾號項目,***產品需要添加一個新的功能。拖拽功能。一聽簡單。百度上輪子挺多,直接拉一個過來用著就行。然鵝。。。興奮之余,卻失望至極。東西很多,沒有一個能使得。你讓我失望,那我就讓你絕望。於是,拖拽的故事就開始了。。

vue拖拽功能組件源碼

vue拖拽功能

必備知識點:

先給不懂的童鞋補充下流程,文章要細讀方能拖動元素到你心裏~

按下的時候,我們需要獲取

元素當前的 具有相對定位元素的左側距離

元素當前的具有相對定位元素的頂部距離

鼠標按下點的x軸距離(鼠標左側的距離)

鼠標按下點的y軸距離 (鼠標頂部的距離)

獲取到這些點,先存儲起來,後面的計算需要用到這些值

  start(e){
      // 如果touches存在就說明是移動端
      // 否則為pc端直接獲取事件源對象
      let touch = e.touches? e.touches[0] : e;
      this.position.x = touch.clientX;
      this.position.y = touch.clientY;
      this.dx = moveDiv.offsetLeft;
      this.dy = moveDiv.offsetTop;
  }

Step1.

讓元素跟著鼠標的移動不斷移動。既然鼠標的x軸和y軸可以獲取到,那我們就可以通過計算來讓元素實現移動。

移動的時候,我們需要獲取並設置

鼠標此時的當前的x軸和y軸的距離

鼠標點擊的x軸和y軸的距離(按下的時候定義過)

此時用移動的距離 - 點擊的起始位置就是移動的距離。

賦值給點擊元素的left和top即可。

補充:計算的方式很多種,這知識其中一種

  move(e){
      let touch = e.touches? e.touches[0] : e;
      this.nx = touch.clientX - this.position.x;
      this.ny = touch.clientY - this.position.y;
      
this.xPum = this.dx+this.nx; this.yPum = this.dy+this.ny; moveDiv.style.left = this.xPum + "px"; moveDiv.style.top = this.yPum + "px"; },

Step2.

離開的時候,我們需要擡起和移動事件從棧中清除掉,並且在結束時對邊界做一個處理。不讓元素拖動到屏幕外面,否則的話,不小心拖出去了,拉都拉不回來。這就很尷尬了。

元素的寬度

父元素的寬度和高度

元素的左側距離 + 元素的寬度

元素的頂部距離 + 元素的高度

end(e){
      let oWidth = moveDiv.offsetWidth; // Element Width
      let oWrapWidth = moveDiv.parentNode.offsetWidth; // Parent Element Width
      let oWrprapHeight = moveDiv.parentNode.offsetHeight; // Parent Element Height
      let sumWidth = moveDiv.offsetLeft + oWidth; // Element Left + Element Width
      let sumHeight = moveDiv.offsetTop + moveDiv.offsetHeight; // Element Top + Element Height
      // The Limit Deal
      if(moveDiv.offsetLeft < 0) {
          moveDiv.style.left = 0;
      } else if(sumWidth > oWrapWidth){
          moveDiv.style.left = oWrapWidth - oWidth + ‘px‘;
      } else if(moveDiv.offsetTop < 0) {
          moveDiv.style.top = 0;
      } else if(sumHeight > oWrprapHeight) {
          moveDiv.style.top = oWrprapHeight - moveDiv.offsetHeight + ‘px‘;
      }
      document.onmousemove = null;
      document.onmouseup = null;
  }

組件源碼

考慮到復用性,pc和移動端。

<template>
  <!--S 拖動組件 -->
    <div class="drag" id="moveDiv"
        @mousedown="start($event)" @touchstart="start($event)"
        @mousemove="move($event)" @touchmove="move($event)"
        @mouseup="end($event)" @touchend="end($event)">
        <slot name="drag-cont"></slot>
    </div><!--E 拖動組件 -->
  </template>
  <script>
  export default {
    data() {
      return {
        position: {x: 0,y: 0}, // 鼠標點擊的x軸和y軸的距離
        nx: ‘‘,    // 鼠標當前距離元素的左側距離
        ny: ‘‘,    // 鼠標當前距離元素的頂部距離
        dx: ‘‘,    // 元素距離左側的距離
        dy: ‘‘,    // 元素距離頂部的距離
        xPum: ‘‘,  // 元素移動的x軸距離
        yPum: ‘‘,  // 元素移動的y軸距離
      }
    },
    methods: {
      start(e){
        // 如果touches存在就說明是移動端
        // 否則為pc端直接獲取事件源對象
        let touch = e.touches? e.touches[0] : e;
        this.position.x = touch.clientX;
        this.position.y = touch.clientY;
        this.dx = moveDiv.offsetLeft;
        this.dy = moveDiv.offsetTop;
      },
      move(e){
        let touch = e.touches? e.touches[0] : e;
        this.nx = touch.clientX - this.position.x;
        this.ny = touch.clientY - this.position.y;
        this.xPum = this.dx+this.nx;
        this.yPum = this.dy+this.ny;
        moveDiv.style.left = this.xPum + "px";
        moveDiv.style.top = this.yPum + "px";
        document.addEventListener("touchmove",function(){
            event.preventDefault();
        },false);
        if(e.preventDefault){
          e.preventDefault();
          }else{
          window.event.returnValue == false;
        }
      },
      end(e){
        let oWidth = moveDiv.offsetWidth; // Element Width
        let oWrapWidth = moveDiv.parentNode.offsetWidth; // Parent Element Width
        let oWrprapHeight = moveDiv.parentNode.offsetHeight; // Parent Element Height
        let sumWidth = moveDiv.offsetLeft + oWidth; // Element Left + Element Width
        let sumHeight = moveDiv.offsetTop + moveDiv.offsetHeight; // Element Top + Element Height
        // The Limit Deal
        if(moveDiv.offsetLeft < 0) {
          moveDiv.style.left = 0;
        } else if(sumWidth > oWrapWidth){
          moveDiv.style.left = oWrapWidth - oWidth + ‘px‘;
        } else if(moveDiv.offsetTop < 0) {
          moveDiv.style.top = 0;
        } else if(sumHeight > oWrprapHeight) {
          moveDiv.style.top = oWrprapHeight - moveDiv.offsetHeight + ‘px‘;
        }
        document.onmousemove = null;
        document.onmouseup = null;
      }
    }
  }
  </script>
  ?
  <style lang="less" scoped>
  .drag {
    position: absolute;
    left: 0;
    right: 0;
    z-index: 999;
  }
  </style>

引入Demo

    
 <Drag class="drag">
        <div slot="drag-cont">訂單記錄</div>
      </Drag>
  <style>
    .drag {
      width: .6rem;
      height: .6rem;
      background-color: rgba(0, 0, 0,.55);
      text-align: center;
      line-height: .6rem;
      font-size: .14rem;
      color: #ffffff;
    }
  </style>

使用的時候,給組件添加類名,添加樣式即可。

Vue拖拽組件