js触摸事件详细解读

本文来自火狐浏览器官方文档 https://developer.mozilla.org/zh-CN/docs/Web/API/Touch_events

触摸事件(touch event)可响应用户手指(或触控笔)对屏幕或者触控板操作,给基于触控的用户界面提供了可靠支持。

触摸事件接口是较为底层的 API,可为特定程序提供多点触控交互(比如双指手势)的支持。多点触控交互开始于一个手指(或触控笔)开始接触设备平面的时刻。随后其他手指也可触摸设备表面,并随意进行划动。当所有手指离开设备平面时,交互结束。整个交互期间,程序接收开始、移动、结束三个阶段的触摸事件。

触摸事件与鼠标事件类似,不同的是触摸事件还提供同一表面不同位置的同步触摸。TouchEvent 接口将当前所有活动的触摸点封装起来。Touch 接口表示单独一个触摸点,其中包含参考浏览器视角的相对坐标。

定义

表面(surface)
可感知触摸的平面,可以是屏幕或触控板。
触摸点(touch point)
表面上的一个接触点.。有可能是手指 (或者胳膊肘、耳朵、鼻子都行。但一般是手指) 或者触摸笔.

接口

TouchEvent
表示位于表面上的一个触摸点的某个状态发生改变时产生的事件。
Touch
表示用户与触摸表面间的一个单独的接触点。
TouchList
表示一组 Touch,用于多点触控的情况。

示例

本示例通过对多个触控点进行同步跟踪,让用户通过多点触控的方式在 <canvas> 元素上用两个(或以上)手指同时画图。本示例只在支持触摸事件的浏览器下生效。

注:下文中用“手指”表示与平面的交互,当然触控笔等也是可行的。

创建画布

<canvas id="canvas" width="600" height="600" style="border:solid black 1px;">
  你的浏览器不支持 canvas 元素。
</canvas>
<br>
日志:<pre id="log" style="border: 1px solid #ccc;"></pre>

设置事件处理器

当页面加载时,下文的 startup() 函数由 window.onload 属性触发。

window.onload = function startup() {
  var el = document.getElementsByTagName("canvas")[0];
  el.addEventListener("touchstart", handleStart, false);
  el.addEventListener("touchend", handleEnd, false);
  el.addEventListener("touchmove", handleMove, false);
  log("初始化成功。")
}

该函数为 <canvas> 元素设置了所有相关的事件监听器,使事件在触发时能够得到处理。

跟踪新触摸

我们将跟踪当前存在的所有触摸点。

var ongoingTouches = [];

当 touchstart 事件触发时,平面上即出现一个新的触摸点,继而调用 handleStart() :

function handleStart(evt) {
  evt.preventDefault();
  console.log("触摸开始。");
  var el = document.getElementsByTagName("canvas")[0];
  var ctx = el.getContext("2d");
  var touches = evt.changedTouches;

  for (var i = 0; i < touches.length; i++) {
    console.log("开始第 " + i + " 个触摸 ...");
    ongoingTouches.push(copyTouch(touches[i]));
    var color = colorForTouch(touches[i]);
    ctx.beginPath();
    ctx.arc(touches[i].pageX, touches[i].pageY, 4, 0, 2 * Math.PI, false);
    // 在起点画一个圆。
    ctx.fillStyle = color;
    ctx.fill();
    console.log("第 " + i + " 个触摸已开始。");
  }
}

event.preventDefault() 阻止了浏览器继续处理触摸(和鼠标)事件。 然后我们取得上下文,从事件的 TouchEvent.changedTouches 属性中获得已改变的触摸点列表。

上述列表中所有的 Touch 对象即为当前所有活动的触摸点,把它们置于一个数组中,然后为每个触摸绘制起点。我们设置线条宽度为四像素,所以恰好会绘制一个半径为 4 像素的圆。

当触摸移动时绘制

在触摸平面上移动一根或者几根手指会触发 touchmove 事件,从而将调用handleMove() 函数。本例中这个函数用于更新触摸点信息,并为每个触摸点从之前位置到当前位置之间绘制直线。

function handleMove(evt) {
  evt.preventDefault();
  var el = document.getElementsByTagName("canvas")[0];
  var ctx = el.getContext("2d");
  var touches = evt.changedTouches;

  for (var i = 0; i < touches.length; i++) {
    var color = colorForTouch(touches[i]);
    var idx = ongoingTouchIndexById(touches[i].identifier);

    if (idx >= 0) {
      log("继续第 " + idx + "个触摸。");
      ctx.beginPath();
      log("ctx.moveTo(" + ongoingTouches[idx].pageX + ", " + ongoingTouches[idx].pageY + ");");
      ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY);
      log("ctx.lineTo(" + touches[i].pageX + ", " + touches[i].pageY + ");");
      ctx.lineTo(touches[i].pageX, touches[i].pageY);
      ctx.lineWidth = 4;
      ctx.strokeStyle = color;
      ctx.stroke();

      ongoingTouches.splice(idx, 1, copyTouch(touches[i])); // 切换触摸信息
      console.log(".");
    } else {
      log("无法确定下一个触摸点。");
    }
  }
}

这个函数不仅对所有已改变的触摸点进行了遍历,还从缓存的触摸信息数组中得到了每个触摸点要绘制的新线段的起点。这是通过读取每个触摸点的 Touch.identifier 属性实现的。对每个触摸点而言,该属性是个唯一的整数,且手指接触表面的整个过程中,这个属性保持不变。

这样我们就可以取得每个触摸点之前位置的坐标,并且使用恰当的上下文方法绘制片段,从而将新旧两个位置连接起来。

当片段绘制完毕后,我们调用 Array.splice() 将 ongoingTouches 数组中触摸点之前的信息替换为当前信息。

触摸结束处理

用户的手指从表面抬起时将触发 touchend 事件。我们通过调用下面的 handleEnd() 函数来处理此类事件。 这个函数的工作就是为每个结束的触摸点绘制最后一个片段,然后将触摸点从 ongoingTouches 数组中移除。

function handleEnd(evt) {
  evt.preventDefault();
  log("触摸结束。");
  var el = document.getElementsByTagName("canvas")[0];
  var ctx = el.getContext("2d");
  var touches = evt.changedTouches;

  for (var i = 0; i < touches.length; i++) {
    var color = colorForTouch(touches[i]);
    var idx = ongoingTouchIndexById(touches[i].identifier);

    if (idx >= 0) {
      ctx.lineWidth = 4;
      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY);
      ctx.lineTo(touches[i].pageX, touches[i].pageY);
      ctx.fillRect(touches[i].pageX - 4, touches[i].pageY - 4, 8, 8);
      // 在终点画一个正方形
      ongoingTouches.splice(idx, 1); // 用完后移除
    } else {
      log("无法确定要结束哪个触摸点。");
    }
  }
}

这个函数与上一个很相像,唯一的实质性区别就是在调用 Array.splice() 时, 我们把用过的触摸实体从 ongoingTouches 数组中直接移除了,不再添加更新信息。对这个触摸点的跟踪随之终止。

触摸取消处理

如果用户的手指不小心滑入浏览器界面,或者触摸需要取消时,会触发 touchcancel 事件。从而会调用下面的 handleCancel() 函数:

function handleCancel(evt) {
  evt.preventDefault();
  console.log("触摸取消。");
  var touches = evt.changedTouches;

  for (var i = 0; i < touches.length; i++) {
    var idx = ongoingTouchIndexById(touches[i].identifier);
    ongoingTouches.splice(idx, 1); // 用完后移除
  }
}

这里的想法是立刻结束触摸,所以我们直接从 ongoingTouches 数组中将其移除,而不去绘制最后的片段。

便捷函数

本例中使用了几个便捷函数,有必要简单了解一下,对理解其它代码很有帮助。

为每个触摸点选择一个颜色

为了区分每个触摸点绘制的内容,我们引入 colorForTouch() 函数,根据每个触摸点所独有的标记设定一个颜色。 这个标记在这里可能是一个无意义的数字,但我们至少可以利用它“对于每个触摸点的值都不同”这一特性。

function colorForTouch(touch) {
  var r = touch.identifier % 16;
  var g = Math.floor(touch.identifier / 3) % 16;
  var b = Math.floor(touch.identifier / 7) % 16;
  r = r.toString(16); // 转换为十六进制字符串
  g = g.toString(16); // 转换为十六进制字符串
  b = b.toString(16); // 转换为十六进制字符串
  var color = "#" + r + g + b;
  log("identifier " + touch.identifier + " 触摸的颜色为:" + color);
  return color;
}

这个函数返回一个表示颜色的字符串,可以在调用 <canvas> 的函数时使用。比如,若 Touch.identifier 的值为 10, 则返回的字符串为 "#aaa"。

译注:这里的 colorForTouch() 不是一个好主意。Touch.identifier 是一个实验性属性,存在兼容性问题,不同浏览器之间实现方法不同,因此会得到不同的结果。

拷贝触摸对象

有些浏览器(比如 mobile Safari)会在不同事件之间复用触摸点对象,因此只复制所需的部分,要优于引用整个对象。

function copyTouch(touch) {
  return { identifier: touch.identifier, pageX: touch.pageX, pageY: touch.pageY };
}

查找触摸点

ongoingTouchIndexById() 函数通过遍历 ongoingTouches 数组来寻找与给定标记相匹配的触摸点,返回该触摸点在数组中的下标。

function ongoingTouchIndexById(idToFind) {
  for (var i=0; i<ongoingTouches.length; i++) {
    var id = ongoingTouches[i].identifier;

    if (id == idToFind) {
      return i;
    }
  }
  return -1;    // 未找到
}

显示后台操作记录

function log(msg) {
  var p = document.getElementById(‘log‘);
  p.innerHTML = msg + "\n" + p.innerHTML;
}

如果你的浏览器支持触摸,就可以 在线试用

jsFiddle 上的示例

附加信息

本节提供了在 web 应用中处理触摸事件的其它信息。

处理点击

由于在 touchstart(或系列 touchmove 事件里的首个)中调用 preventDefault() 也会阻止相应的鼠标事件的触发,因此一般情况下我们在touchmove 而不是 touchstart 中调用它,这样,鼠标事件仍可正常触发,链接等部件也可继续工作。有些框架采取了一个替代方案,使用触摸事件代替鼠标事件来达到相同目的。 (下面的示例过于简单,可能产生奇怪的行为。这里仅仅作为一个引导。)

function onTouch(evt) {
  evt.preventDefault();
  if (evt.touches.length > 1 || (evt.type == "touchend" && evt.touches.length > 0))
    return;

  var newEvt = document.createEvent("MouseEvents");
  var type = null;
  var touch = null;

  switch (evt.type) {
    case "touchstart":
      type = "mousedown";
      touch = evt.changedTouches[0];
      break;
    case "touchmove":
      type = "mousemove";
      touch = evt.changedTouches[0];
      break;
    case "touchend":
      type = "mouseup";
      touch = evt.changedTouches[0];
      break;
  }

  newEvt.initMouseEvent(type, true, true, evt.originalTarget.ownerDocument.defaultView, 0,
    touch.screenX, touch.screenY, touch.clientX, touch.clientY,
    evt.ctrlKey, evt.altKey, evt.shiftKey, evt.metaKey, 0, null);
  evt.originalTarget.dispatchEvent(newEvt);
}

只在第二次触摸时调用 preventDefault()

为了阻止页面产生类似 pinchZoom 的行为,可以通过“在系列触摸点的第二个调用 preventDefault()”技术来实现。但是该技术的行为并没有在触摸事件的标准中做出完整定义,并且在不同浏览器中会产生不同行为(比如,iOS将阻止缩放,但允许二指平移;Android 允许缩放但阻止平移;Opera 和 Firefox 目前会阻止所有缩放和平移操作)。目前,对于此类情况最好依靠 meta viewport 来阻止缩放,而不要依赖于上述行为。

标准

标准 状态 备注
Touch Events – Level 2
Touch
Draft 添加 radiusXradiusYrotationAngle 和 force 属性
Touch Events
Touch
Recommendation 首次引入

浏览器兼容性

Touch

Update compatibility data on GitHub

  Desktop Mobile
  Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome for Android Edge Mobile Firefox for Android Opera for Android Safari on iOS Samsung Internet
Basic support Full support22 Full supportYes Full support52

Notes

打开

No supportNo No supportNo No supportNo Full supportYes Full supportYes Full supportYes Full support6 Full supportYes Full supportYes ?
Touch() constructor

Experimental

Full support48 No supportNo Full support46 No supportNo Full support35 ? Full support48 Full support48 Full supportYes Full support6 Full supportYes Full supportYes Full supportYes
clientX Full support22 Full supportYes Full support52

Notes

打开

No supportNo No supportNo No supportNo Full supportYes Full supportYes Full supportYes Full support6 Full supportYes Full supportYes ?
clientY Full support22 Full supportYes Full support52

Notes

打开

No supportNo No supportNo No supportNo Full supportYes Full supportYes Full supportYes Full support6 Full supportYes Full supportYes ?
force

Experimental

Full supportYes ? Full supportYes ? ? ? Full supportYes Full supportYes ? Full supportYes ? Full supportYes ?
identifier Full support22 Full supportYes Full support52

Notes

打开

No supportNo No supportNo No supportNo Full supportYes Full supportYes Full supportYes Full support6 Full supportYes Full supportYes ?
pageX Full support22 Full supportYes Full support52

Notes

打开

No supportNo No supportNo No supportNo Full supportYes Full supportYes Full supportYes Full support6 Full supportYes Full supportYes ?
pageY Full support22 Full supportYes Full support52

Notes

打开

No supportNo No supportNo No supportNo Full supportYes Full supportYes Full supportYes Full support6 Full supportYes Full supportYes ?
radiusX

Experimental

Full support43 ? ? ? ? ? Full support43 Full support43 ? ? ? Full supportYes ?
radiusY

Experimental

Full support43 ? ? ? ? ? Full support43 Full support43 ? ? ? Full supportYes ?
rotationAngle

Experimental

Full support43 ? ? ? ? ? Full support43 Full support43 ? ? ? Full supportYes ?
screenX Full support22 Full supportYes Full support52

Notes

打开

No supportNo No supportNo No supportNo Full supportYes Full supportYes Full supportYes Full support6 Full supportYes Full supportYes ?
screenY Full support22 Full supportYes Full support52

Notes

打开

No supportNo No supportNo No supportNo Full supportYes Full supportYes Full supportYes Full support6 Full supportYes Full supportYes ?
target Full support22 Full supportYes Full support52

Notes

打开

No supportNo No supportNo No supportNo Full supportYes Full supportYes Full supportYes Full support6 Full supportYes Full supportYes ?

Legend

Full support 
Full support
No support 
No support
Compatibility unknown 
Compatibility unknown
Experimental. Expect behavior to change in the future.
Experimental. Expect behavior to change in the future.
See implementation notes.
See implementation notes.

Firefox,触摸事件以及多进程(e10s)

在 Firefox 中,触摸事件随 e10s(electrolysis 即 多进程 Firefox)的禁用而禁用。e10s 在 Firefox 中默认为可用,但可以在某些特定情形下关闭它,比如在安装一些要求禁用 e10s 的工具或扩展时。这意味着即使在支持触屏的桌面或便携设备上,触摸事件也可能失效。

你可以使用 about:support 查看“应用程序概要”部分中“多进程窗口”一栏来确定 e10s 是否启用。1/1 表示启用,0/1 表示禁用。

如果你想强制性的开启 e10s(来显式重新启用触摸事件支持),你需要使用 about:config 创建一个布尔类型的设置 browser.tabs.remote.force-enable,将它设置为 true,重启浏览器,e10s 将始终启用而不受其他设置的影响。

原文地址:https://www.cnblogs.com/durcaidurcai/p/10400382.html

时间: 2024-10-10 13:29:48

js触摸事件详细解读的相关文章

JS—触摸事件、手势事件

JS-触摸事件.手势事件 dbclick触屏设备不支持双击事件.双击浏览器窗口,会放大画面.可以通过在head标签内加上这么一行: <meta name="viewport" content="width=device-width, minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> 可以实现,我们编写的页面不会随着用的手势而放大缩小.关于meta标签,我还没有研究过,罪过啊. mouse在触屏上

移动端JS 触摸事件基础

一.手机上的触摸事件 基本事件: touchstart   //手指刚接触屏幕时触发 touchmove    //手指在屏幕上移动时触发 touchend     //手指从屏幕上移开时触发 下面这个比较少用: touchcancel  //触摸过程被系统取消时触发 每个事件都有以下列表,比如touchend的targetTouches当然是 0 咯: touches         //位于屏幕上的所有手指的列表 targetTouches   //位于该元素上的所有手指的列表 change

移动端js触摸事件大全

一.手机上的触摸事件 基本事件: touchstart   //手指刚接触屏幕时触发 touchmove    //手指在屏幕上移动时触发 touchend     //手指从屏幕上移开时触发 下面这个比较少用: touchcancel  //触摸过程被系统取消时触发 每个事件都有以下列表,比如touchend的targetTouches当然是 0 咯: touches         //位于屏幕上的所有手指的列表 targetTouches   //位于该元素上的所有手指的列表 change

js 触摸事件 touch

先上实例代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>touch</title> <style t

Android6.0触摸事件分发机制解读

本篇博文是Android触摸事件分发机制系列博文的第一篇,带领大家从全局掌握Android触摸事件分发机制.特别声明的是,本源码解读是基于最新的Android6.0版本. (一)Android6.0源码解读之View点击事件分发机制 (二)Android6.0源码解读之ViewGroup点击事件分发机制 (三)Android6.0源码解读之Activity点击事件分发机制 为什么要解读触摸事件分发机制 1.掌握View事件分发机制 2.为解决View滑动冲突提供理论支持 3.了解Android最

JS事件监听手机屏幕触摸事件 Touch

JS移动客户端--触屏滑动事件 移动端触屏滑动的效果其实就是图片轮播,在PC的页面上很好实现,绑定click和mouseover等事件来完成.但是在移动设备上,要实现这种轮播的效果,就需要用到核心的touch事件.处理touch事件能跟踪到屏幕滑动的每根手指. 以下是四种touch事件 touchstart:     //手指放到屏幕上时触发 touchmove:      //手指在屏幕上滑动式触发 touchend:    //手指离开屏幕时触发 touchcancel:     //系统取

node.js零基础详细教程(4):node.js事件机制、node异步IO操作

第四章 建议学习时间3小时  课程共10章 学习方式:详细阅读,并手动实现相关代码 学习目标:此教程将教会大家 安装Node.搭建服务器.express.mysql.mongodb.编写后台业务逻辑.编写接口,最后完成一个完整的项目后台,预计共10天课程. node.js事件机制 node.js是单线程,但是通过事件和回调支持并发,可以实现非常高的性能. node.js所有的API都是通过异步调用.第一堂课的时候,我们写过一个同步和异步的示例(如下),当初说到:同步代码先执行完成,然后才执行异步

quojs 及 转:11个处理触摸事件和多点触摸的JS库

QuoJs官方文档http://www.360doc.com/content/15/0504/18/11984479_468037372.shtml ==== 11个处理触摸事件和多点触摸的JS库 摘要:触摸屏是现在所有智能手机的标配,还包括各种平板设备,而且很多桌面也慢慢在开始支持触摸操作.要开发支持触摸屏设备的Web应用,我们需要借助浏览器的触摸事件来实现. 触摸屏是现在所有智能手机的标配,还包括各种平板设备,而且很多桌面也慢慢在开始支持触摸操作.要开发支持触摸屏设备的Web应用,我们需要借

react-native 手势响应以及触摸事件的处理

react-native 的触摸事件: TouchableHighlight , TouchableNativeFeedBack , TouchableOpacity , TouchableWithoutFeedBack. 在onPress事件触发的函数中都会携带事件参数(event)包含一个参数 :nativeEvent 参数如下 locationX 和 locationY 是触摸的位置相对于组件的位置 pageX 和 pageY 是触摸的位置相对于屏幕的位置 timestamp 是时间戳 手