学会Pointer指针事件 ,一套拖拽事件两端(PC端、移动端)跑

985 阅读4分钟

早期浏览器很low,它只存在鼠标事件(MouseEvent)。随时代的发展出现了智能手机、平板电脑等触屏设备,交互方式发生了变化,单纯的鼠标事件已不够开发人员使用了。于是引入了触摸事件(TouchEvent)。不过这还不够完美,没有把触控笔事件考虑进去。当要求移动端、PC端同时具备拖拽功能时,开发人员还要维护两份事件逻辑。

为了解决上述问题,官方引入了全新的规范Pointer指针事件(Pointer) ,它提供了一套统一的事件,鼠标、触摸、触控笔事件一锅端了,不需要再维护两套事件逻辑。

Pointer指针事件属性

Pointer继承MouseEvent事件,因此常用属性clientX,clientY等指针事件都具备,同时指针事件也扩展了它自己独有的属性。

属性介绍
pointerId指针引起的事件的唯一标识
width指针的接触面的CSS像素宽度
height指针的接触面的CSS像素高度
pressure指针输入的压力值,范围在0-1之间
tangentialPressure切向压力值,范围在-1-1]之间,0表示控制设备中立状态时的值
tiltX由输入设备(如手写笔)与Y轴的构成平面,和YZ平面之间的夹角,范围在-90-90之间
tiltY由输入设备(如手写笔)与X轴构成平面,和XZ平面之间的夹角,范围在-90-90之间
twist输入设备(如手写笔)围绕自身范围旋转的角度,范围在0-359之间
pointerType表示触发事件的设备类型,mouse,pen,touch
isPrimary表示一个指针是否是当前设备类型的主指针

以上属性使用场景我没想到,有大佬的话可以指点下。

Pointer事件类型

Pointer有不同的事件类型,与鼠标事件一样有相同的语义话表示(down, up, move, over, out, enter, leave)。

事件类型事件介绍
pointerover当定点设备进入某个元素的命中检测 范围时触发。
pointerenter当定点设备进入某个元素或其子元素的命中检测范围时,或做为某一类不支悬停(hover)状态的设备所触发的poinerdown事件的后续事件时所触发。(详情可见 pointerdown事件类型).
pointerdown当某指针得以激活时触发。
pointermove当某指针改变其坐标时触发。
pointerup当某指针不再活跃时触发。
pointercancel当浏览器认为某指针不会再生成新的后续事件时触发(例如某设备不再活跃)
pointerout可能由若干原因触发该事件,包括:定位设备移出了某命中检测的边界;不支持悬浮状态的设备发生pointerup事件(见pointerup事件); 作为 pointercancel event事件的后续事件(见pointercancel事件);当数位板检测到数位笔离开了悬浮区域时。
pointerleave当定点设备移出某元素的命中检测边界时触发。对于笔形设备来说,当数位板检测到笔移出了悬浮范围时触发。
gotpointercapture当某元素接受到一个指针捕捉时触发。
lostpointercapture当针对某个指针的指针捕捉得到释放时触发。

指针、鼠标及触摸事件对比:

MouseEventTouchEventPointerEvent
mousedowntouchstartpointerdown
mousemovetouchmovepointermove
mouseuptouchendpointerup
touchcancelpointercancel
mouseenterpointerenter
mouseleavepointerleave
mouseoverpointerover
mouseoutpointerout
gotpointercapture
lostpointercapture

Pointer事件的使用

先看看鼠标实现拖拽效果:

<div id="app"></div>
<script>
    const app = document.getElementById('app')
    let isPointerDown = false

    app.addEventListener('mousedown', function (e) {
        isPointerDown = true
    });

    document.addEventListener('mousemove', function (e) {
        if (isPointerDown) {
            const left = app.getBoundingClientRect().left
            const top = app.getBoundingClientRect().top
            let newLeft = e.clientX - left
            let newTop = e.clientY - top
            console.log(newLeft, newTop);
            app.style.left = newLeft + left - app.clientWidth / 2 + 'px'
            app.style.top = newTop + top - app.clientHeight / 2 + 'px'
        }
    });

    document.addEventListener('mouseup', function (e) {
        isPointerDown = false
    });
</script>

电脑、移动设备分别访问链接,出现的效果是电脑可以拖拽,移动设备不支持。如果想要移动设备满足拖拽要单独使用触摸事件再写一套。

可以点击这里体验:code.juejin.cn/pen/7250291…

用Pointer事件实现拖拽:

<div id="app"></div>
<script>
  const app = document.getElementById('app')
  let isPointerDown = false

  app.addEventListener('pointerdown', function (e) {
      isPointerDown = true
  });

  app.addEventListener('pointermove', function (e) {
      //捕获
      app.setPointerCapture(e.pointerId)
      if (isPointerDown) {
          const left = app.getBoundingClientRect().left
          const top = app.getBoundingClientRect().top
          let newLeft = e.clientX - left
          let newTop = e.clientY - top
          app.style.left = newLeft + left - app.clientWidth / 2 + 'px'
          app.style.top = newTop + top - app.clientHeight / 2 + 'px'
      }
  });

  app.addEventListener('pointerup', function (e) {
      isPointerDown = false
  });
</script>

Pointer事件与鼠标事件使用存在差异,Pointer使用setPointerCapture API做为捕获。

使用Pointer事件后电脑、移动设备都能进行拖拽。

可以点击这里体验: code.juejin.cn/pen/7250289…

移动设备拖拽效果图:

Pointer -middle-original.gif

总结

Pointer指针事件帮助我们通过一份代码,同时处理鼠标,触摸和触控笔事件,能为开发者节省掉时间。避免维护多套事件逻辑,做到一套事件逻辑两端跑。

如果我的文章对你有帮助,您的👍就是对我的最大支持^_^。

往期文章:linglan01.cn/about