移动端div实现页面任意位置拖拽(TS)

3,271 阅读2分钟

移动端触摸事件

  • touchstart 当在屏幕上按下手指时触发 (对应PC mousedown)
  • touchmove 当在屏幕上移动手指时触发 (对应PC mousemove)
  • touchend 当在屏幕上抬起手指时触发 (对应PC mouseup)
  • touchcancel 当一些更高级别的事件发生的时候(如电话接入或者弹出信息)会取消当前的touch操作,即触发touchcancel。一般会在touchcancel时暂停游戏、存档等操作。

每个触摸事件都包括了三个触摸列表,每个列表里包含了对应的一系列触摸点(用来实现多点触控):

  • touches:当前位于屏幕上的所有手指的列表
  • targetTouches:位于当前DOM元素上手指的列表
  • changedTouches:涉及当前事件手指的列表

每个 Touch 对象包含的属性如下:

  • clientX:触摸目标在视口中的x坐标。

  • clientY:触摸目标在视口中的y坐标。

  • identifier:标识触摸的唯一ID。

  • pageX:触摸目标在页面中的x坐标。

  • pageY:触摸目标在页面中的y坐标。

  • screenX:触摸目标在屏幕中的x坐标。

  • screenY:触摸目标在屏幕中的y坐标。

  • target:触摸的DOM节点目标。

DOM结构

 <div v-show="showBackIndex" :class="homeBth" id="moveDiv"
         @mousedown="down($event)" @touchstart="down($event)"
         @mousemove="move($event)" @touchmove="move($event)"  
         @mouseup="end($event)" @touchend="end($event)" @click="goIndex">
      <img src="../../assets/images/arrow-1.png" class="icon"/>
      <span>首页</span>
    </div> 

本来是用的vant的van-button标签,增加拖拽功能时换成了div

定义的变量

  private flags: any = false;
  private position: any = {x: 0, y: 0};
  private nx: any = '';
  private ny: any = '';
  private dx: any = '';
  private dy: any = '';
  private xPum: any = '';
  private yPum: any = '';

方法

// 实现移动端拖拽
  private down (e: any) {
    let moveDiv = document.getElementById('moveDiv'); // 根据id获取DOM元素
    this.flags = true;
    let touch;
    if (e.touches) {
      touch = e.touches[0];
    } else {
      touch = e;
    }
    this.position.x = touch.clientX;
    this.position.y = touch.clientY;
    this.dx = moveDiv!.offsetLeft; // ts会提示moveDiv可能为空,此时要么判空,要么还可通过变量后添加 ! 操作符告诉 TypeScript 该变量此时非空
    this.dy = moveDiv!.offsetTop;
  }

  private move (e: any) {
    let moveDiv = document.getElementById('moveDiv');
    if (this.flags) {
      let touch;
      if (e.touches) {
        touch = e.touches[0];
      } else {
        touch = 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',  () => { // 如果碰到滑动问题,请注意是否获取到 touchmove
        e.preventDefault(); // jq 阻止冒泡事件
        // e.stopPropagation(); // 如果没有引入jq 就用 stopPropagation()
      }, {passive: false}); // addEventListener()的第三个参数传入对象{passive:false},只是false不生效
    }
  }

// 鼠标释放时候的函数
  private end () {
    this.flags = false;
  }
}

参考文章

vue 移动端 实现div拖拽移动

TS传递引用,提示对象可能为空(react版本)

addEventListener第三个参数passive的问题