《WebKit 技术内幕》学习之十三(1):移动WebKit

1 触控和手势事件

1.1 HTML5规范

        随着电容屏幕的流行,触控操作变得前所未有的流行起来。时至今日,带有多点触控功能已经成为了移动设备的标准配置,基于触控的手势识别技术也获得巨大的发展,如使用两个手指来缩放应用的大小等。所以,在移动系统中,编程需要考虑的不是鼠标事件,而是触控和手势事件,这些事件对于改善用户体验起了非常大的作用。最早将触控和手势事件引入Web领域的是苹果公司,它在iOS2.0中加入了这种支持,随后Android系统也加入了这一阵营。

        在介绍规范之前,有必要先理解一下触控、手势事件与浏览器默认行为的关系。图13-1描述了处理触控事件的可能情况,图中灰色圆圈表示的是一个触控点,当它向上移动的时候,浏览器已面临艰难选择,对于用户触发的触控事件,可能有两个地方需要使用到触控事件:第一是浏览器本身,浏览器可能希望利用这个事件完成翻页动作;另外一方面,该灰色圆圈的部分所对应的元素可能需要由自己来处理这些触控事件,而不是浏览器来处理。浏览器或者WebKit的具体处理逻辑我们在稍后会介绍到。

                                    图13-1 浏览器处理的触控事件

        目前,Web领域引入两种与触控相关的技术,其一是HTML5 Touch Events,它基本上已经成为了规范,得到了众多渲染引擎和浏览器的支持和认可。其二是Gesture Events,它是苹果公司设计并在Safari浏览器中实现的,但是没有得到其他更多浏览器的支持。下面分别来分析这两者。

        首先是HTML5 Touch Events,它已经成为推荐的规范,而且事实上也得到了两家主流移动操作系统中浏览器的支持,可以说发展得非常好,该标准主要是定义如何将原始的触控事件以特定的方式传递给JavaScript引擎,然后再传递给注册的事件响应函数。这一规范在HTML5网页应用中已经比较成熟,网页开发者可以根据规范进行定义,其中最主要的接口是TouchEvent,定义在图13-2中上半部分,表示一次传递给JavaScript注册函数的事件。

                                图13-2 HTML5 Touch Events定义的TouchEvent接口

         根据标准中的定义,TouchEvent分成4种类型:touchstart、touchmove、touchend和touchcancel。熟悉触控事件的读者可能很容易理解,它们分别表示触控点开始接触屏幕、触控点移动、触控点离开屏幕和触控点取消。最后一个类型理解起来比较困难,有时浏览器取消该触控点,可能因为其他一些原因,如它可能进入了其他的窗口等。TouchEvent当然还是继承自DOM的UIEvent,这表明它有同其他事件类似的处理方式,不同点在于这个事件有一些不同的属性。下面逐一来分析它们。

  • “touches” :表示当前屏幕中包括的所有触控点,“touches”是一个列表,如果触控点大于1,表示这是一个支持多点触控的设备。
  • “targetTouches” :表示的是当前所有起始于当前DOM元素的触控点,也就是如果一个触控点的“touchstart”事件发生的位置在该元素的区域内,那就会被包含在该列表中。
  • “changedTouches” :表示发生变化的触控点。如果类型是“touchstart”,那就包含新的触控点。如果是“touchmove”,那就包含发生移动的触控点。而“touchend”就是指触控点移出了屏幕。

每个触控点都需要包含很多信息,也就是图13-2中的众多属性,主要是标记属性的唯一ID、触控的目标(也就是对于的DOM元素)、屏幕位置、视图中的位置等,看起来还是比较直观的。有了这些接口,JavaScript代码能够非常清楚地知道每个触控点的信息,就能够像本地代码一样使用它们来满足各种应用的需求。

使用的方法并不复杂,示例代码13-1展示了如何注册监听事件的处理函数,这同其他的DOM事件区别并不是特别大,而且也只能注册在特定的元素(称为Clickable Element)上,如“div”等。因为TouchEvent有四种类型,示例代码定义了其中三种类型触控事件的处理函数。以“touchstart”为例,它会接受一个事件,就是之前定义的TouchEvent接口,为了避免同浏览器行为的冲突,可以在最开始调用“preventDefault”,这在第5章也做过介绍。后面可以根据事件来做出相应的动作。

示例代码13-1 使用HTML5 Touch Events的JavaScript代码

    var targetElement = document.getElementById("aTouchableElement");targetElement.addEventListener("touchstart", onTouchStartEvent, false);targetElement.addEventListener("touchmove", onTouchMoveEvent, false);targetElement.addEventListener("touchend", onTouchEndEvent,false);function onTouchStartEvent(event) {// 处理事件event.preventDefault();event.touches;event.targetTouches;event.changedTouches;}…

        有了这些原始的触控事件,Web开发者可以在网页中使用JavaScript代码来识别这些原始触控事件并生成手势事件,如Long Press、Pinch、Swipe、Fling等手势事件。目前有很多库提供这样的实现,如jQuery Mobile、Sencha Touch等,这极大地方便了Web开发者。

        除了原始的触控事件,苹果公司开发的Safari浏览器还支持向JavaScript代码提供Gesture Events,其含义是由浏览器来识别原始事件并将手势事件传递给JavaScript代码,当然它定义了一个新的GestureEvent接口,事件类型也分为gesturestart、gesturechange和gestureend。这里的手势事件并没有与上面定义的Pinch等采用同样的方式,而是将旋转角度和缩放大小数据传递给JavaScript,这更像是支持两个手指的触控事件。由于它的局限性和不够通用,所以并没有得到像原始触控事件一样比较广泛的支持,这里也不做过多的介绍。

1.2 工作原理

        WebKit和Chromium是如何支持触控事件的呢?其实这是比较复杂的过程,特别是某些处理方式跟鼠标事件其实还是有不一样的地方。首先事件的派送机制依然是使用第5章介绍的捕获和冒泡机制,具体参看图5-18的过程。

图13-3描述WebKit处理触控事件所使用到的一些主要类和它们之间的关系。最下层的WebWidget和WebView是WebKit的Chromium移植提供的接口,同之前介绍的一样,它们也是被Chromium项目的代码所调用,当Chromium接收到事件之后会将其传给WebViewImpl这个非常重要的类来处理。这个类大家应该很熟悉了,因为已经见过很多次面了。因为事件有多种类型,WebViewImpl类借助于PageWidgetDelegate类来处理和区分这些输入事件。经过PageWidgetDelegate类处理后的事件会调用WebViewImpl类各个事件处理接口,而WebViewImpl类的这些接口基本上使用主框(Frame)的事件处理句柄EventHandler对象来处理事件。细心的读者可以发现,图中的EventHandler包含两个函数,第一个是处理原始触控事件的函数,第二则是处理手势事件的函数。为什么会这样呢?

                                图13-3 WebKit处理触控事件的基础设施

        WebKit除了接收原始的触控事件之外,还需要它的移植或者说是浏览器提供手势事件,这些事件会触发WebKit的默认动作。例如“LongPress”事件,它表示手指在屏幕上长按一段时间,这需要浏览器将其识别成手势事件然后传递给WebKit,当WebKit接收到这个事件之后,触发自己的默认动作。这个事件同前面介绍的Safari提供的Gesture Events不是一回事,因为Safari只是提供了旋转和缩放的值给JavaScript,而这里的手势事件包括一个或者多个手指触发的动作,WebKit并不会将这里的手势事件传递给JavaScript代码,如“longPress”事件会触发浏览器弹出右键菜单的动作。

        对于多框结构的网页,事件首先由WebKit交给主框处理,WebKit会检查该事件是否需要由子框处理,如果是的话,WebKit会将该事件派发给子Frame,依此类推。这是一个递归过程,请读者结合第三章介绍的框结构来理解该过程。

        下面来分析一下在Chromium中浏览器是如何处理从系统传递过来的触控事件,并将它们转换成之后的手势事件的。这一过程稍显复杂,让我们来解释一下原因。当触控事件发生后,Chromium首先需要将触控事件保存,然后使用众多的手势识别器(Gesture Recognizers)来将其识别成手势事件。此时,如下面所描述的问题来了。

  • Chromium是否需要将所有的原始触控事件传递给网页呢?答案是否定的。如一些网页并没有注册监听函数来处理它们,那么就会造成极大的浪费,因为这些事件的传递和处理是个稍长的过程。更为致命的是,一个简单的用户操作通常有非常多的事件,这会极大地浪费CPU等资源。
  • 为什么需要Gesture Event传递给WebKit呢?因为是由浏览器识别并将识别出结果的事件传递给WebKit,这客观上能够有效减少很多事件的传递。
  • 除了发送TouchEvent和GestureEvent之外,也可能会发送MouseEvent,这是为什么?原因很简单,因为目前还存在一些网页,它们需要监听鼠标相关的事件以完成特定的动作,如果Chromium不模拟这些事件,那么网页显然不能正常的工作。但是某些鼠标事件可以模拟,如MouseDown其实对应于TouchStart,MouseUp对应用TouchEnd等。但是MouseOver就比较麻烦,比如一些网页需要根据当前鼠标悬浮事件来显示一个菜单,这对于触控设备来说,的确是一个问题。

        对于Chromium来说,事件的处理还是相当复杂的,因为需要三种类型的事件并将其传递给WebKit。由于触控事件最初是应用在移动设备上的,所以这里也主要以Chromium的Android版为例来介绍,而Chromium的桌面版对触控事件的支持目前还不是特别完善。

        在Chromium的Android版中,所有的事件都是由Android系统传送过来的,这也意味着事件的处理首先是在Java层,当然是在Browser进程的主线程中,如图13-4所示为层次结构图和相关层次中的基础设施。Java层主要包含两个类。

图13-4 Chromium处理触控事件的基础设施

  • ContentViewGestureHandler :它主要有几个任务。首先,它需要通过相应的设施来决定是否需要原始的触控事件,这其实依赖于WebKit,在每个“touchstart”事件开始的时候,需要进行HitTest检查,该动作检查当前触控点所对应的元素,然后检查该元素是否注册了监听事件的函数,如果是,需要将原始事件传送给WebKit。其次是各种手势事件的识别器,它们能够对WebKit所需要的各种手势进行识别并传递给WebKit,最后根据需要(如果有鼠标事件的监听函数)模拟鼠标事件。
  • ContentViewCore类 :主要负责将C++中的功能桥接到Java层中,并将Java中处理好的事件等信息桥接到C++代码中,它对应C++中的类是ContentViewCoreImpl。

        两个类主要负责Java层的事件处理和传递。

        在Java层之下是著名的RenderWidgetHostView类,它表示一个网页的视图。虽然这是Browser进程中的代理类,表示的是Renderer进程中相应的网页视图,它被ContentViewCoreImpl用来将事件传递给Renderer进程。后面大家应该比较清楚了,Chromium通过IPC机制来完成传递,Browser进程中的基础类是ImmediateInputRouter,而Renderer进程中的基础类是RenderWidget类。

        在Renderer进程中,RenderWidget在Chromium中表示网页的结构,它拥有前面WebKit定义的接口类WebWidget,这样,完整的过程就被这些类串联起来了,如图13-4所示。

1.3 启示和实践

        示例代码13-1其实是一个非常典型的用法,只是对于鼠标、触控等类型的事件处理过程可能需要复杂一些的步骤。

        网页除了可能需要自身处理触控事件以外,还有一个比较特别的问题,那就是对于一个为移动设备定制的网页,它可能不需要使用缩放网页(使用Pinch手势的浏览器默认行为来放大或者缩放网页)或者不需要翻滚网页(Fling手势的浏览器默认行为是滚动网页),因开发者已经考虑并设计出了适合移动设备网页阅读的网页了。那有没有办法帮助开发者和浏览器合力规避浏览器默认行为呢?

        根据上面的描述,相信读者已经看出一些端倪了,那就是网页开发者可以注册事件的响应函数,并调用“preventDefault”函数来阻碍浏览器执行默认行为。问题是这一方法只是针对某个元素而已,而不是整个网页,只是当手指触控到该元素的时候才禁止默认行为。解决这一问题的方法很简单,那就是可以将函数注册到区域更大的元素,如示例代码13-2所示的使用“body”元素就可以解决这个问题。

        示例代码13-2 使用触控事件的响应函数来禁止网页的方法和滚动的代码

    function handleEvent(event) {event.preventDefault();…}document.body.addEventListener('touchstart', handleEvent, false);document.body.addEventListener('touchmove', handleEvent, false);document.body.addEventListener('touchend', handleEvent, false);

        这个方法看起来还是需要一些代码,虽然只是短短的不到十行代码,但是除此以外还有一个更好更简单的办法,那就是使用“meta”标签。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/648324.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DAY11_(简易版)VUEElement综合案例

目录 1 VUE1.1 概述1.1.1 Vue js文件下载 1.2 快速入门1.3 Vue 指令1.3.1 v-bind & v-model 指令1.3.2 v-on 指令1.3.3 条件判断指令1.3.4 v-for 指令 1.4 生命周期1.5 案例1.5.1 需求1.5.2 查询所有功能1.5.3 添加功能 2 Element2.0 element-ui js和css和字体图标下载2.1 …

Vulnhub靶场DC-6

攻击机192.168.223.128 靶机192.168.223.134 主机发现:nmap -sP 192.168.223.0/24 端口扫描 nmap -sV -p- -A 192.168.223.134 开启了22 80端口,80是apache 2.4.25 先进入web界面看一下 用ip进不去,应该被重定向到wordy.com vim /etc/hosts 加上 19…

亚信安慧AntDB构建未来数据库典范

亚信安慧AntDB是一款数据库管理系统,它采用全球影响力大、社区繁荣、开放度高、生态增长迅速的PG内核。这款系统具有卓越的性能和稳定性,在全球范围内备受用户青睐。 与此同时,AntDB的社区也是充满活力的,用户可以在社区中交流经…

Vue中使用TypeScript:全面指南和最佳实践

🚀 欢迎来到我的专栏!专注于Vue3的实战总结和开发实践分享,让你轻松驾驭Vue3的奇妙世界! 🌈✨在这里,我将为你呈现最新的Vue3技术趋势,分享独家实用教程,并为你解析开发中的难题。让我们一起深入Vue3的魅力,助力你成为Vue大师! 👨‍💻💡不再徘徊,快来关注…

WebSocket服务端数据推送及心跳机制(Spring Boot + VUE):

文章目录 一、WebSocket简介:二、WebSocket通信原理及机制:三、WebSocket特点和优点:四、WebSocket心跳机制:五、在后端Spring Boot 和前端VUE中如何建立通信:【1】在Spring Boot 中 pom.xml中添加 websocket依赖【2】…

都学Python了,C++难道真的用不着了吗?

都学Python了,C难道真的用不着了吗? 在开始前我分享下我的经历,刚入行时遇到一个好公司和师父,给了我机会,两年时间从3k薪资涨到18k的, 我师父给了一些【C 】学习方法和资料,让我不断提升自己…

单片机介绍

本文为博主 日月同辉,与我共生,csdn原创首发。希望看完后能对你有所帮助,不足之处请指正!一起交流学习,共同进步! > 发布人:日月同辉,与我共生_单片机-CSDN博客 > 欢迎你为独创博主日月同…

关于axios给后端发送数据的问题

这里需要用的插件:qs.js,是前端给后端发送的数组,需要序列化所以要用到这个插件,这里就提取连接在这里,需要的自提,需要导如进来,别忘记了 链接:https://pan.baidu.com/s/1qyD8v9wfd…

拓展全球市场:静态代理IP成为跨境电商战略的关键工具

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…

EIGRP实验

实验大纲 一、基本配置 1.构建网络拓扑结构图 2.路由器基本配置 3.配置PC 4.测试连通性 5.保存配置文件 二、配置EIGRP 1.查看路由表 2.配置EIGRP动态路由 3.查看路由器路由表 4.测试网络连通性 5.查看所有路由器的路由协议 6.保存配置文件 三、配置OSPF 1.配置…

SpringMVC-对静态资源的访问

1.工程中加入静态资源 在webapp下创建static文件夹,此文件夹专门放入静态资源 2.使项目可以处理静态资源的请求 在SpringMVC配置文件中添加以下语句 1.引入命名空间 xmlns:mvc"http://www.springframework.org/schema/mvc" xsi:schemaLocation“http…

Influxdb系列(二)influx Cli工具操作influxdb

一、安装并使用 influx CLI 客户端下载地址:https://docs.influxdata.com/influxdb/v2/tools/influx-cli/ [root192 bin]# tar -xvzf influxdb2-client-2.7.3-linux-amd64.tar.gz [root192 bin]# cp influx /usr/local/bin/二、客户端方式创建用户 相关的官网地址…

HNSW算法

From: HNSW算法(nsmlib/hnswlib)-CSDN博客HNSW算法的基本原理及使用 - 知乎 HNSW是一种广泛使用的ANN图索引结构,包括DiskANN、DF-GAS、SmartSSD等。本文档主要总结HNSW的结构与工作流程,便于后期研究其工作流程在迁移到CSD中存在的I/O问题…

JVM篇----第八篇

系列文章目录 文章目录 系列文章目录前言一、标记清除算法( Mark-Sweep)二、复制算法(copying)三、标记整理算法(Mark-Compact)前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分…

华媒舍:15种媒体发稿推广的创意理念与案例分析

媒体发稿已经成为推广知名品牌、产品与服务关键方式之一。怎样通过媒体发稿提升曝光度和吸引住受众却是一个挑战。下面我们就详细介绍15种创意理念和案例分析,帮助你更好地进行新闻媒体发稿推广。 1.造就日常生活小故事通过展示真实用户故事和感受,读者对…

Java实现APK检测管理系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 开放平台模块2.3 软件档案模块2.4 软件检测模块2.5 软件举报模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 开放平台表3.2.2 软件档案表3.2.3 软件检测表3.2.4 软件举报表 四、系统展示五、核心代…

Redis 线程模型

更多内容,前往个人博客 一、概述 【1】Redis 是基于 Reactor 模式开发的网络事件处理器:这个处理器被称为文件事件处理器(file event handler),这个文件事件处理器是单线程的,所以 Redis 才叫做单线程的模型…

Unity 责任链模式(实例详解)

文章目录 示例1:游戏事件处理系统示例2:UI消息处理链示例3:游戏内物理碰撞响应链示例4:AI决策链示例5:场景切换责任链示例6:输入命令处理链 责任链模式(Chain of Responsibility)在U…

SpringBoot01

一、SpringBoot项目中常见的依赖 1.1、spring-boot-starter-parent 这个是SpringBoot项目必须导入的依赖,这个父模块内部定义了springboot整合各个技术的依赖版本,降低版本的冲突。 <parent><artifactId>spring-boot-starter-parent</artifactId><group…

玩转未来:Sui游戏峰会将于3月19日亮相GDC

Sui将在今年三月份的旧金山游戏开发者大会&#xff08;Game Developer Conference, GDC&#xff09;上推出其首个重大游戏活动&#xff0c;展示其为独立游戏到3A游戏提供动力&#xff0c;并为游戏开发人员开启吸引新玩家参与的能力。“Play Beyond&#xff1a;Sui游戏峰会”&am…