《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.rhkb.cn/news/245230.html

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

相关文章

基于SSM的蛋糕甜品店管理系统(有报告)。Javaee项目。ssm项目。

演示视频: 基于SSM的蛋糕甜品店管理系统(有报告)。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构,通过Spring…

C++ 数论相关题目(欧拉函数、筛法求欧拉函数)

1、欧拉函数 给定 n 个正整数 ai ,请你求出每个数的欧拉函数。 欧拉函数的定义 1∼N 中与 N 互质的数的个数被称为欧拉函数,记为 ϕ(N) 。 若在算数基本定理中,Npa11pa22…pamm ,则: ϕ(N) Np1−1p1p2−1p2…pm−1p…

SpringBoot项目多数据源配置与MyBatis拦截器生效问题解析

在日常项目开发中,由于某些原因,一个服务的数据源可能来自不同的库,比如: 对接提供的中间库,需要查询需要的数据同步数据,需要将一个库的数据同步到另一个库,做为同步工具的服务对接第三方系统…

肺癌相关文献6

第十四篇 Classification of lung adenocarcinoma based on stemness scores in bulk and single cell transcriptomes IF:6.0 中科院分区:2区 生物学WOS分区:Q1被引次数: 4 背景:癌细胞具有无限期自我更新和增殖的能力[2]。在一…

JavaScript进阶:WebAPIs重点知识整理1

目录 1 DOM修改元素内容 2 DOM修改元素常见属性 3 修改元素样式属性 3.1 通过style修改元素样式 3.2 通过类名className修改元素样式 3.3 通过classList修改元素样式 4 操作表单元素属性 5 自定义属性 6 定时器 7 事件监听 7.1 点击事件 click 7.2 鼠mouseenter和移…

Laya3.0 相机使用

摄像机,是3D场景里边最经常使用的对象了。 官方文档:点击这里学习 1.投影 Projection 透视: 模拟人眼的视觉效果,近大远小。模拟物理世界的规律,将眼睛或相机抽象成一个点,此时视锥体内的物体投影到视平…

YOLO 自己训练一个模型

一、准备数据集 我的版本是yolov8 8.11 这个目录结构很重要 ultralytics-main | datasets|coco|train|val 二、训练 编写yaml 文件 # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] path…

Java项目:基于SSM框架实现同城蔬菜配送管理系统(SSM+B/S架构+源码+数据库+毕业论文)

一、项目简介 本项目是一套ssm825基于SSM框架实现同城蔬菜配送管理系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试&…

【Web前端开发基础】CSS3之空间转换和动画

CSS3之空间转换和动画 目录 CSS3之空间转换和动画一、空间转换1.1 概述1.2 3D转换常用的属性1.3 3D转换:translate3d(位移)1.4 3D转换:perspective(视角)1.5 3D转换:rotate3d(旋转&a…

集美大学“第15届蓝桥杯大赛(软件类)“校内选拔赛 D矩阵选数

经典的状态压缩DP int dp[15][(1<<14)10]; int a[15][15]; void solve() {//dp[i][st]考虑到了第i行 并且当前考虑完第i行以后的选择状态是st的所有方案中的最大值for(int i1;i<13;i)for(int j1;j<13;j)cin>>a[i][j];for(int i1;i<13;i){for(int j0;j<…

Web网页生成桌面应用

前言&#xff1a;网页生成桌面指的是将一个网页保存为桌面应用程序的形式&#xff0c;使得用户可以在桌面上直接打开该网页&#xff0c;而不必通过浏览器打开。这种桌面应用程序一般具有独立的窗口、菜单、工具栏等界面元素&#xff0c;能够提供更加方便快捷的使用体验。 实现…

宠物互联网医院系统

在数字时代&#xff0c;宠物医疗迎来了一场革新&#xff0c;动物互联网医院系统以其先进的技术和智能的特性成为宠物护理的领军者。本文将介绍宠物互联网医院系统的一些关键技术和代码示例&#xff0c;揭示这一科技奇迹的实现原理。 1. 远程医疗服务的实现 远程医疗服务是宠…

谷粒商城配置虚拟机

一、创建虚拟机 之前有在VM里面建一个ubuntu的虚拟机&#xff0c;准备拿来直接用&#xff0c;网络设置为NAT模式&#xff0c;查看我的虚拟机是虚拟机&#xff1a;192.168.248.128 主机&#xff1a; 192.168.2.12。可以互相ping通。 二、linux安装docker Docker docker是虚拟…

无人机航迹规划(六):七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划(提供MATLAB代码)

一、七种算法&#xff08;DBO、LO、SWO、COA、LSO、KOA、GRO&#xff09;简介 1、蜣螂优化算法DBO 蜣螂优化算法&#xff08;Dung beetle optimizer&#xff0c;DBO&#xff09;由Jiankai Xue和Bo Shen于2022年提出&#xff0c;该算法主要受蜣螂的滚球、跳舞、觅食、偷窃和繁…

【医学图像数据增强】切割-拼接(CS-DA)

切割-拼接CS-DA CS-DA 核心思想自然图像和医学图像之间的关键差异CS-DA 步骤确定增强后的数据数量 代码复现 CS-DA 核心思想 论文链接&#xff1a;https://arxiv.org/ftp/arxiv/papers/2210/2210.09099.pdf 大多数用于医学分割的数据增强技术最初是在自然图像上开发的&#x…

Spring Cloud 系列:基于Seata 实现 XA模式

https://seata.io/zh-cn/docs/user/mode/xa https://seata.io/zh-cn/docs/dev/mode/xa-mode XA 规范 是 X/Open 组织定义的分布式事务处理&#xff08;DTP&#xff0c;Distributed Transaction Processing&#xff09;标准&#xff0c;XA 规范 描述了全局的TM与局部的RM之间的…

C++入门学习(十五)运算符

算术运算符&#xff1a;用于处理四则运算赋值运算符&#xff1a;用于将表达式的值赋给变量比较运算符&#xff1a;用于表达式的比较&#xff0c;并返回一个真值或假值逻辑运算符&#xff1a;用于根据表达式的值返回真值或假值 一、加减乘除 #include <iostream> #incl…

Simulink|光伏并网逆变器低电压穿越仿真模型

目录 主要内容 模型研究 1.模型总览 2.boost模块 3.Inverter模块 4.控制模块 5.信号模块 结果一览 下载链接 主要内容 该模型为光伏逆变器低电压穿越仿真模型&#xff0c;采用boost加NPC拓扑结构&#xff0c;基于MATLAB/Simulink建模仿真。模型具备中点平衡…

【AI视野·今日Robot 机器人论文速览 第七十五期】Thu, 11 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Thu, 11 Jan 2024 Totally 16 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Analytical Model and Experimental Testing of the SoftFoot: an Adaptive Robot Foot for Walking over Obstacles and Irre…

解决Windows下Goland的Terminal设置为Git Bash失败

路径不要选错了&#xff1a; 如果还是不行&#xff1a; 把bash路径加进去试试 goland设置Terminal