vue移动端实现,DOM元素拖拽放大缩小,改变位置

先介绍一下,我们的应用场景,就是一种图片,能编辑的那种,

主要是:拖动可以该变位置,还可以实现图片的缩小放大。

实现思路是:  通过绝对定位+触摸事件( @touchend @touchstart @touchmove

注意: 以上三个事件是移动端才有,PC端上不会生效!!!!!!

好了:整理好思路就开始码代码吧

 这是我的demo,这样我先把代码贴出来吧,以下是实现的所有代码, 各处代码有详细的注释,如有不解,欢迎评论,或者私信,看到即回    以下带直接新建.vue文件复制即可 

<template>
  <div>
    <h4>移动端拖拽事件,案例</h4>
    <!-- 父盒子 用于限制其拖拽范围 -->
    <div class="max-box">
      <!-- 被拖拽元素   拖拽之后可改变其大小和位置-->
      <div class="min-box"
           ref="context"
           @touchend="touchEnd"
           @touchstart="touchStart"
           @touchmove="touchMove">
 <!-- 图片元素宽高均设置100%这样我们只需要关注,父盒子的宽高就好,至于会变形,哈,那是用户操作的,和我有什么关系,哈哈哈  -->
        <img width="100%"   
             height="100%"
             src="@/assets/logo.png"
             alt="" />
        <!-- 该元素是拖拽点用于实现元素的放大和缩小 
          
        要添加.stop修饰符,是因为,父元素也有这个事件,所以阻止事件冒泡,真好用,哈哈哈
-->
        <div class="drag-box"
             @touchend.stop="touchEndDrag"
             @touchstart.stop="touchStartDrag"
             @touchmove.stop="touchMoveDrag">
  <!-- 这是一个elemant UI的 图标,可以随时替换哈
-->
          <i class="el-icon-refresh-left"></i>  
        </div>
      </div>
    </div>
  </div>
</template>

<script>


export default {
  data () {
    return {
    
      touchX: 0,  //触摸点X坐标
      touchY: 0,   //触摸点Y坐标
      contextTop: 0,  //拖拽区域距离顶部的距离 
      contextLeft: 0,  //拖拽区域距离左边的距离
      contextWidth: 0,  //拖拽区域的宽度
      contextHeight: 0,  //拖拽区域的高度

      newTouchX: 0,  //拖拽区域的新的X坐标
      newTouchY: 0,  // 拖拽区域的新的Y坐标


      dragBoxtouchX: 0,  //拖拽区域距离左部的距离
      dragBoxtouchY: 0,  //拖拽区域距离顶部的距离
      newContextWidth: 0,  //拖拽新的区域的宽度
      newContextHeight: 0,  //拖拽新的区域的高度
    }
  },
  mounted () {

    /* 
      注意:如果你的dom是此时没有,就获取不到相关信息,就是 0。因此你应该在dom显示出来之后,从$nextTick中获取。  此时获取的就是最新的信息, 此处是一个坑  就会导致拖动出现bug
    */
   /*

        这是初始的一些信息
*/
    this.contextTop = this.$refs.context.offsetTop;  //拖拽区域距离顶部的距离
    this.contextLeft = this.$refs.context.offsetLeft;  //拖拽区域距离左边的距离
    this.contextWidth = this.$refs.context.offsetWidth;  //拖拽区域的宽度
    this.contextHeight = this.$refs.context.offsetHeight;  //拖拽区域的高度
  },
  methods: {
    //  以下这三个事件对应 拖动改变位置
    touchStart (e) {  // 这是  触摸开始的事件

      this.touchX = e.changedTouches[0].pageX;  //触摸点X坐标  记录开始坐标
      this.touchY = e.changedTouches[0].pageY;  //触摸点Y坐标
    },
    touchMove (e) {   // 触摸过程中的  事件
      var touchX = e.changedTouches[0].pageX; //触摸点X坐标   这是当前触摸位置的坐标
      var touchY = e.changedTouches[0].pageY; //触摸点Y坐标
      let x = touchX - this.touchX;  //X轴移动距离
      let y = touchY - this.touchY;  //Y轴移动距离
      let newY = this.contextTop + y;  //拖拽区域的新的Y坐标    初始的坐标加上移动的就是新的坐标
      let newX = this.contextLeft + x;  //拖拽区域的新的X坐标
      if (newY >= (500 - Math.abs(this.contextHeight))) {  //  以下四个判断是解决 拖动的边界问题,不能超出父元素的大小,  500就是父元素的宽度 和高度 
        newY = 500 - Math.abs(this.contextHeight);  //
      }
      if (newY <= 0) {  // 当小于0时限制不能超出
        newY = 0;
      }
      if (newX >= (500 - Math.abs(this.contextWidth))) {  // 改变 left 时要减去 拖动元素的宽度,又因为这个元素的宽度是不固定因此要用一个变量,也就是为什么开始时要获取的原因。 Math.abs() 表示取绝对值
        newX = 500 - Math.abs(this.contextWidth);
      }
      if (newX <= 0) {
        newX = 0;
      }
      this.$refs.context.style.top = `${newY}px`;   // 新的高度赋值给拖动的元素
      this.$refs.context.style.left = `${newX}px`;
      this.newTouchX = x + this.contextLeft;   // 新的位置重新保存一下
      this.newTouchY = y + this.contextTop;
    },
    touchEnd () {
      this.contextTop = this.newTouchY;    // 新的位置 保存给 初始的变量也更新一下,此处应该可以优化以下
      this.contextLeft = this.newTouchX;
    },

// 以下三个事件 就是拖动角标的 放大和缩小事件   和上面的区别就在于 他改变的是元素的宽度和高度,而上面改变的是元素的top 和 left 偏移量。
 
touchMoveDrag 区别主要是这个方法,


    touchStartDrag (e) {
      this.dragBoxtouchX = e.changedTouches[0].pageX;
      this.dragBoxtouchY = e.changedTouches[0].pageY;
      console.log(this.touchX, this.touchY, '开始拖拽');
    },
    touchMoveDrag (e) {
      var touchX = e.changedTouches[0].pageX;
      var touchY = e.changedTouches[0].pageY;
      let x = touchX - this.dragBoxtouchX;
      let y = touchY - this.dragBoxtouchY;
      this.newContextWidth = this.contextWidth + x;
      this.newContextHeight = this.contextHeight + y;
      //  以下四个判断是用来解决 边界问题 
      if (this.newContextWidth >= (500 - Math.abs(this.contextLeft))) {  // 新的元素宽度是要减去自己的偏移量,用来限制不能超出 父盒子 500 的宽和高
        // console.log('超出范围', this.contextLeft);
        if (this.contextLeft < 0) {  // 该判断用来限制如果时负值 就有可能超出的问题
          this.newContextWidth = 500
        }
        else {
          this.newContextWidth = 500 - Math.abs(this.contextLeft);
        }
      }
      if (this.newContextWidth <= 40) {  // 此处用来限制拖动的大小,即,拖动最小值是40*40,下面的判断是高度的限制同理
        this.newContextWidth = 40;
      }
      if (this.newContextHeight >= (500 - Math.abs(this.contextTop))) {
        // console.log('超出范围', this.contextTop);
        if (this.contextTop < 0) {
          this.newContextHeight = 500
        } else {
          this.newContextHeight = 500 - Math.abs(this.contextTop);
        }
      }
      if (this.newContextHeight <= 40) {
        this.newContextHeight = 40;
      }
      this.$refs.context.style.width = `${this.newContextWidth}px`;   // 计算之后的高度和宽度直接设置给元素即可
      this.$refs.context.style.height = `${this.newContextHeight}px`;
      // console.log(touchX, touchY, '移动位置');
    },
    touchEndDrag (e) {
      console.log(e);   // 拖动结束再次保存 新的位置 ,
      this.contextWidth = this.newContextWidth;
      this.contextHeight = this.newContextHeight;
    },
    
  },
}
</script>

<style lang="less" scoped>
.max-box {
  width: 500px;
  height: 500px;
  overflow: hidden;  // 限制 内部元素不能超出
  background-color: rgb(98, 190, 255);
  position: relative;  // 开启定位,子元素需要绝对定位
  .min-box {
    width: 100px;
    height: 100px;
    background-color: rgb(155, 255, 33);
    position: absolute;   // 开启绝对定位
    top: 100px;  // 设值初始位置
    left: 100px;   
    .drag-box {
      width: 20px;
      height: 20px;
      background-color: rgb(255, 255, 255);
      text-align: center;
      line-height: 20px;
      position: absolute;   // 缩放图标设置位置 
      right: -10px;
      bottom: -10px;
      border-radius: 50%;
    }
  }
}
</style>

猜你喜欢

转载自blog.csdn.net/qq_46634851/article/details/126429867