zoukankan      html  css  js  c++  java
  • 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 {
           .6rem;
          height: .6rem;
          background-color: rgba(0, 0, 0,.55);
          text-align: center;
          line-height: .6rem;
          font-size: .14rem;
          color: #ffffff;
        }
      </style>

    使用的时候,给组件添加类名,添加样式即可。

  • 相关阅读:
    IOS GCD使用实例大全
    IOS GCD图片数据异步下载,下载完成后合成显示
    Git使用详细教程
    maven是干什么的?
    npm 的作用
    webstorm+nodejs环境中安装淘宝镜像
    关于框架搭建-web
    ES6-babel转码
    JavaScript单元测试工具-Jest
    webpack-dev-server和webpack
  • 原文地址:https://www.cnblogs.com/bgwhite/p/10399211.html
Copyright © 2011-2022 走看看