移动端事件(Touch触摸和Pointer指针)

5,322 阅读4分钟

移动端事件有哪些

  • Touch触摸事件
  • Pointer指针事件

移动端事件的发展

  • 没有移动端事件,大部分鼠标事件在移动端一样有用
  • 苹果推出Touch触摸事件
  • 微软推出Pointer指针事件(统一鼠标、触摸、笔)

兼容性(can i use)

  • 移动和pc都适配推荐使用Pointer指针事件

Touch触摸事件

Touch事件基础

Touch事件的类型

注意事项

Touch事件的特征检测

1.Touch 事件的类型
  • touchstart 元素上触摸开始时触发
  • touchmove 元素上触摸移动时触发
  • touchend 手指从元素上离开时触发
  • touchcancel 触摸被打断时触发
const $box = document.getElementById('box');

$box.addEventListener('touchstart', startHandler, false);
$box.addEventListener('touchmove', moveHandler, false);
$box.addEventListener('touchend', endHandler, false);
$box.addEventListener('touchcancel', cancelHandler, false); //右键弹出菜单,电话和弹窗进入

function startHandler() {
    console.log('touchstart');
}
function moveHandler() {
    console.log('touchmove');
}
function endHandler() {
    console.log('touchend');
}
function cancelHandler() {
    console.log('touchcancel');
}
2.注意事项
  • Touch 事件在 PC 端不会触发,鼠标事件在 PC 端和移动端都会触发
  • 即使触摸点移出目标元素,touchmove 事件依然会持续触发,mousemove 事件不会再触发
  • 触发 touchmove 与 touchend 事件,一定要先触发 touchstart
$box.addEventListener('mouseover', mouseHandler, false);
$box.addEventListener('mouseenter', mouseHandler, false);
$box.addEventListener('mousedown', mouseHandler, false);
$box.addEventListener('mousemove', mouseHandler, false); //移动端会阻止 只能点击触发
$box.addEventListener('mouseup', mouseHandler, false);
$box.addEventListener('mouseout', mouseHandler, false);
$box.addEventListener('mouseleave', mouseHandler, false);
$box.addEventListener('click', mouseHandler, false);

function mouseHandler(evt) {
    console.log(evt.type);
}
3.Touch 事件的特征检测(判断浏览器支不支持 Touch 事件)
//console.log('onload' in window);
console.log('ontouchstart' in window);
if ('ontouchstart' in window) {
    console.log('支持');
}

Touch事件的event对象

event对象的常用属性

触摸点的常用属性

阻止浏览器的默认行为

1.event 对象的常用属性
  • type 事件类型
  • target 目标元素
  • touches 屏幕上的所有触摸点
  • targetTouches 起始于目标上的所有触摸点
  • changedTouches 事件触发时,状态发生了改变的所有触摸点
$box.addEventListener('touchstart', startHandler, false);
function startHandler(evt) {
    console.log('touchstart');
    console.log(evt);
    console.log(evt.type);
    console.log(evt.target);
    console.log(evt.touches);
    console.log(evt.targetTouches);
    console.log(evt.changedTouches);
}


2.触摸点的常用属性
  • identifier 触摸点id(唯一标识符),一般多指触摸有用
  • target 目标元素
  • screenX/screenY 触点相对于屏幕左边缘的X、Y坐标
  • clientX/clientY 触摸点相对于可视区左边缘的X,Y坐标 (不计算滚动条)
  • pageX/pageY 触摸点相对于页面左边缘的X,Y坐标 (计算滚动条)
$box.addEventListener('touchstart', startHandler, false);
$box.addEventListener('touchend', endHandler, false);
$box.addEventListener('touchcancel', cancelHandler, false);
function startHandler(evt) {
    const touch = evt.changedTouches[0];
    console.log(touch);
    console.log(touch.identifier); 
    console.log(touch.target); 
    console.log(touch.screenX, touch.screenY); 
    console.log(touch.clientX, touch.clientY);
    console.log(touch.pageX, touch.pageY); 
}
function endHandler(evt) {
    console.log('touchend');
    console.log(evt.touches.length);
    console.log(evt.targetTouches.length);
    console.log(evt.changedTouches.length);
}
function cancelHandler(evt) {
    console.log('touchcancel');
    console.log(evt.touches.length);
    console.log(evt.targetTouches.length);
    console.log(evt.changedTouches.length);
}
3.阻止浏览器的默认行为
  • 阻止 scrolling, pinch/zoom, 鼠标事件等默认行为
<style>
    .box {
        width: 200px;
        height: 200px;
        background-color: red;

        /* 处理所有触摸操作 */
        /* touch-action: auto; */
		  
         /* 禁止平移和缩放 */
        /* touch-action: none; */

        /* 平移 */
        /* touch-action: pan-x; */
        /* touch-action: pan-y; */

        /* 只允许进行滚动和持续缩放操作,不允许双击缩放 */
        /* touch-action: manipulation; */
    }
</style>
function startHandler(evt) {
    evt.preventDefault();
}

$box.addEventListener('mouseover', mouseHandler, false);
$box.addEventListener('mouseenter', mouseHandler, false);
$box.addEventListener('mousedown', mouseHandler, false);
$box.addEventListener('mousemove', mouseHandler, false);
$box.addEventListener('mouseup', mouseHandler, false);
$box.addEventListener('mouseout', mouseHandler, false);
$box.addEventListener('mouseleave', mouseHandler, false);
$box.addEventListener('click', mouseHandler, false);

function mouseHandler(evt) {
    console.log(evt.type);
}

单指拖拽

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>单指拖拽</title>
    <style>
      .box {
        width: 200px;
        height: 200px;
        background-color: red;
      }
    </style>
  </head>
  <body style="height: 2000px">
    <div id="box" class="box"></div>

    <script>
      const drag = $el => {
        // 每次拖拽最开始的触摸点
        const startPoint = {};
        // 拖拽过程中移动到的点
        const movePoint = {};
        // 被拖拽元素的当前位置
        const curPos = {
          x: 0,
          y: 0
        };

        $el.addEventListener('touchstart', startHandler, false);
        $el.addEventListener('touchmove', moveHandler, false);
        $el.addEventListener('touchend', endHandler, false);
        $el.addEventListener('touchcancel', endHandler, false);

        function startHandler(evt) {
          //阻止拖拽产生的滚动条
          evt.preventDefault();

          const touch = evt.changedTouches[0];

          startPoint.x = touch.pageX;
          startPoint.y = touch.pageY;

          // console.log(startPoint);
        }
        function moveHandler(evt) {
          const touch = evt.changedTouches[0];

          movePoint.x = curPos.x + touch.pageX - startPoint.x;
          movePoint.y = curPos.y + touch.pageY - startPoint.y;

          $el.style.transform = `translate3d(${movePoint.x}px,${movePoint.y}px,0)`;
        }
        function endHandler() {
          curPos.x = movePoint.x;
          curPos.y = movePoint.y;
        }
      };

      drag(document.getElementById('box'));
    </script>
  </body>
</html>

应用场景

  • touchstart 事件可用于元素触摸的交互,比如页面跳转,标签页切换

  • touchmove 事件可用于页面的滑动特效,网页游戏,画板

  • touchend 事件主要跟 touchmove 事件结合使用

  • touchcancel 使用率不高

Pointer指针事件

Pointer事件基础

1.Pointer 事件的类型

pointerover/pointerenter/pointerout/pointerleave/pointerdown/pointermove/pointerup/pointercancel

// pointer
$box.addEventListener('pointerover', pointerHandler, false);
$box.addEventListener('pointerenter', pointerHandler, false);
$box.addEventListener('pointerdown', pointerHandler, false);
$box.addEventListener('pointermove', pointerHandler, false);
$box.addEventListener('pointerup', pointerHandler, false);
$box.addEventListener('pointerout', pointerHandler, false);
$box.addEventListener('pointerleave', pointerHandler, false);
2.注意事项
  • Pointer 事件直接继承了鼠标事件,在此基础上又添加了其他一些内容,处理 Pointer 事件和处理鼠标事件几乎一致
  • Pointer 事件在 PC 端和移动端都会触发
  • 触摸点移出目标元素,touchmove 事件依然会持续触发,pointermove 和 mousemove 事件不会再触发
3.Pointer 事件的特征检测(判断浏览器支不支持 Pointer 事件)
if ('onpointerdown' in window) {
    console.log('支持 Pointer 事件');
}

Pointer事件的event对象

event对象的常用属性 阻止浏览器的默认行为

1.event对象的常用属性
  • pointerId 指针id(唯一标识符)

  • type 事件类型

  • pointerType 指针类型(鼠标/笔/触摸等)

  • target 目标元素

  • screenX/screenY 指针相对于屏幕左边缘的X、Y坐标

  • clientX/clientY 指针相对于可视区域左边缘的X、Y坐标。不包括任何滚动偏移

  • x/y clientX/clientY 的别名

  • pageX/pageY 指针相对于 HTML 文档左边缘的X、Y坐标。包括滚动偏移

$box.addEventListener('pointerover', pointerHandler, false);
$box.addEventListener('pointerenter', pointerHandler, false);
$box.addEventListener('pointerdown', pointerHandler, false);
$box.addEventListener('pointermove', pointerHandler, false);
$box.addEventListener('pointerup', pointerHandler, false);
$box.addEventListener('pointerout', pointerHandler, false);
$box.addEventListener('pointerleave', pointerHandler, false);
$box.addEventListener('pointercancel', pointerHandler, false);

function pointerHandler(evt) {
    console.log(evt);
    console.log(evt.pointerId);
    console.log(evt.type);
    console.log(evt.pointerType);
    console.log(evt.target);
    console.log(evt.screenX, evt.screenY);
    console.log(evt.clientX, evt.clientY);
    console.log(evt.x, evt.y);
    console.log(evt.pageX, evt.pageY);
}
2.阻止浏览器的默认行为
  • 阻止 scrolling, pinch/zoom, 鼠标事件等默认行为
  • Pointer 的事件处理函数中,evt.preventDefault() 阻止的是 PC 端的默认行为(不能阻止 scrolling, pinch/zoom, 鼠标事件等默认行为,可以阻止图片拖动的默认行为)
  • 可以在 touch 的事件处理函数中使用 evt.preventDefault() 阻止移动端的默认行为
  • touch-action 设置触摸操作时浏览器的默认行为(touch-action: none;阻止所有默认)


$box.addEventListener('pointerover', pointerHandler, false);
$box.addEventListener('pointerenter', pointerHandler, false);
$box.addEventListener('pointerdown', pointerHandler, false);
$box.addEventListener('pointermove', pointerHandler, false);
$box.addEventListener('pointerup', pointerHandler, false);
$box.addEventListener('pointerout', pointerHandler, false);
$box.addEventListener('pointerleave', pointerHandler, false);
$box.addEventListener('pointercancel', pointerHandler, false);
function pointerHandler(evt) {
     evt.preventDefault();
}


$box.addEventListener('touchstart', startHandler, false);
function startHandler(evt) {
    阻止移动端默认行为
    evt.preventDefault();
}

单指拖拽

const drag = $el => {
    // 每次拖拽最开始的触摸点
    const startPoint = {};
    // 拖拽过程中移动到的点
    const movePoint = {};
    // 被拖拽元素的当前位置
    const curPos = {
        x: 0,
        y: 0
    };

    $el.addEventListener('pointerdown', startHandler, false);
    // $el.addEventListener('pointermove', moveHandler, false);
    // $el.addEventListener('pointerup', endHandler, false);
    // $el.addEventListener('pointercancel', endHandler, false);
    $el.addEventListener(
        'touchstart',
        evt => {
            evt.preventDefault();
        },
        false
    );

    function startHandler(evt) {
        startPoint.x = evt.pageX;
        startPoint.y = evt.pageY;

        document.addEventListener('pointermove', moveHandler, false);
        document.addEventListener('pointerup', endHandler, false);
        document.addEventListener('pointercancel', endHandler, false);
    }
    function moveHandler(evt) {
        evt.preventDefault();

        movePoint.x = curPos.x + evt.pageX - startPoint.x;
        movePoint.y = curPos.y + evt.pageY - startPoint.y;

        $el.style.transform = `translate3d(${movePoint.x}px, ${movePoint.y}px, 0)`;
    }
    function endHandler() {
        curPos.x = movePoint.x;
        curPos.y = movePoint.y;

        document.removeEventListener('pointermove', moveHandler, false);
        document.removeEventListener('pointerup', endHandler, false);
        document.removeEventListener('pointercancel', endHandler, false);
    }
};

drag(document.getElementById('box'));

IOS手势事件

该事件只有IOS上的浏览器支持!

  • gesturestart : 手指触碰当前元素,屏幕上有两个或者两个以上的手指
  • gesturechange : 手指触碰当前元素,屏幕上有两个或者两个以上的手指位置在发生移动
  • gestureend : 在gesturestart后, 屏幕上只剩下两根以下(不包括两根)的手指

手势事件 touchEvent 的属性

  • 属性 rotation : 表示手指变化引起的旋转角度,负值表示逆时针旋转,正值表示顺时针旋转。
  • 属性 scale : 表示两个手指间距离的变化情况(例如向内收缩会缩短距离);这个值从 1 开始,并随距离拉大而 增长,随距离缩短而减小。根据我们的生理极限,不允许出现负值

手势模拟

gesture

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>手势模拟</title>
    <style>
      img {
        width: 100%;
      }
      .box {
        width: 200px;
        height: 200px;
        background-color: red;
      }
    </style>
  </head>
  <body>
    <img id="gesture" src="./gesture.png" alt="移动端手势" />

    <!-- <div id="box" class="box"></div> -->

    <script>
      // 1.滑(扫)动手势
      function swipe($el, cb) {
        // 最开始的触摸点
        const start = {};
        // 时间和距离阈值
        const threshold = {
          time: 500,
          distance: 100
        };

        $el.addEventListener('pointerdown', startHandler, false);
        // 阻止移动端默认行为
        $el.addEventListener(
          'touchstart',
          evt => {
            evt.preventDefault();
          },
          false
        );

        function startHandler(evt) {
          // 阻止 PC 端默认行为
          evt.preventDefault();

          start.time = new Date().getTime();
          start.x = evt.pageX;
          start.y = evt.pageY;

          document.addEventListener('pointerup', endHandler, false);
          document.addEventListener('pointercancel', endHandler, false);
        }
        function endHandler(evt) {
          const delta = {};
          let direction = '';

          delta.time = new Date().getTime() - start.time;
          delta.x = evt.pageX - start.x;
          delta.y = evt.pageY - start.y;

          // 判断是否是扫动手势
          if (
            delta.time > threshold.time ||
            (Math.abs(delta.x) < threshold.distance &&
              Math.abs(delta.y) < threshold.distance)
          ) {
            // 扫太慢或扫的距离太短,不是扫动手势
            return;
          } else {
            // 判断扫动方向
            if (Math.abs(delta.x) >= Math.abs(delta.y)) {
              // 左右扫动
              if (delta.x > 0) {
                // 右扫
                direction = 'right';
              } else {
                // 左扫
                direction = 'left';
              }
            } else {
              // 上下扫动
              if (delta.y > 0) {
                // 下扫
                direction = 'down';
              } else {
                // 上扫
                direction = 'up';
              }
            }

            cb.call($el, direction);
          }

          document.removeEventListener('pointerup', endHandler, false);
          document.removeEventListener('pointercancel', endHandler, false);
        }
      }

      // swipe(document.getElementById('box'), function (direction) {
      //   // console.log(this);
      //   console.log(direction);
      // });

      swipe(document.getElementById('gesture'), function (direction) {
        // console.log(this);
        console.log(direction);
      });

      // 作业:使用 touch 事件模拟扫动手势

      // 2.手势库 Hammer.js
      // https://hammerjs.github.io/
    </script>
  </body>
</html>

幻灯片的扫动切换

之前已经实现过了PC幻灯片键盘切换 现在使用Point对幻灯片进行滑动切换

具体代码看本目录 ---> (幻灯片的扫动切换)

import Slider from './slider.js';
const $el = document.querySelector('.slider');
const sliderInstance = new Slider($el);

swipe($el, function (direction) {
    if (direction === 'left') {
        //   切换下一张
        sliderInstance.next();
    } else if (direction === 'right') {
        //   切换上一张
        sliderInstance.prev();
    }
});

总结

事件类型

image-20210808132605132

注意事项

image-20210808132753289

image-20210808133531920

特征检测

image-20210808134159315

event对象

image-20210808134326813

image-20210808134459376

阻止浏览器的默认行为

  • 阻止scrolling, pinch/zoom,鼠标事件等默认行为

image-20210808134733323

60d401b409d89cd719541968