视频链接:
片 1
上节课我们介绍了富文本组件 rich-text,及如何用它解析 HTML 源码。这节课我们开始介绍 view 组件,它是小程序最基础的容器组件,基本使用它可以实现所有我们常见的 UI 布局。
小程序相比 HTML5 网页,在交互上有一个不可忽略的优势,就是小程序里的单击事件,没有 300 毫秒的延迟,而在 HTML5 网页上,单击链接或按钮,会明显感觉到有一个卡顿,这涉及到苹果系统里一个重要的功能设计,这节课我们看看这是怎么回事。
首先我们先看一看 view 这个组件。
view 是最基础的,也是微信小程序第一个公布的容器组件。所谓容器组件,就像 HTML 里的 div 标签一样,是为容纳其它组件而存在的。它本身也可以有一些自己的样式,但它最重要的功能,是布局。
这个容器组件,有这些属性我们需要注意。
片 2
这个属性指定按下去的类样式,让容器有一个单击效果。当 hover-class="none" 时,或者没有设置这个属性时,就没有点击态效果。单击、再松开手指后,容器组件恢复之前的状态。
从示例中看到,当按下去时,view 容器应用了 bc_red 样式,松开后,UI 恢复如初(见上面示例代码)。
(可以从视频中查看运行效果)
hover-class 这个属性名称有一定迷惑性。在 HTML 开发中,mousehover 事件指的是鼠标悬停事件,hover 有悬停的意思,mousedown 才是鼠标按下去的事件。在 Flash AS3 开发中,鼠标按下去显示的帧,也是 mousedown。view 的这个 hover-class 属性,可以理解为 press-class。
片 3
这个属性可以阻止父节点出现点击态,默认为 false,不阻止。
从示例代码看到,有两个 view 容器,里面那个子容器 view 使用了 hover-stop-propagation 属性(见上面代码)。由于它是一个布尔属性,只要写上属性名,不填写属性值也代表真。如果写属性值的话,还要使用布尔值绑定,直接写一个字符串"true",是不行的。
在运行效果中,子容器有点击态,父容器没有,虽然父容器也设置了 hover-class 属性,但触碰事件被子容器阻止了。
(可以从视频中查看运行效果)
与 hover-class 一样,hover-stop-propagation 这个属性也有一些迷惑性,官方文档对它的解释是,“指定是否阻止本节点的祖先节点出现点击态”,这个描述是很专业的。虽然是“点击态”,但并不能理解为是 press-stop-propagation 或 click-stop-propagation,虽然它是这个意思。
现在我们通过跟踪父子组件的 tap 事件,验证一下 hover-stop-propagation 属性的作用。
片 4
在示例中,我们给两个view,一对父子容器同时绑定 tap 事件。为方便追踪,为父子容器都分配了 id。父容器 id 是 parentView,子容器是 childView。(见上面代码)
单击一次父容器,输出一次。但单击一次子容器,却输出两次。为什么会输出两次?为什么会触发两次 tap 事件呢? (见上面代码)
这是因为每个事件都有捕捉、目标与冒泡三个阶段(见上面图例),在 view 视图容器上使用 bind 绑定的事件,默认会在目标与冒泡两个阶段派发事件。
子组件的冒泡事件默认会向上传递。hover-stop-propagation 属性就是为了阻止父组件出现hover-class样式,但是它还不能阻止冒泡事件向上传递。当设置该属性后,这时我们单击子组件,仍然可以看到两次输出。
(可以从视频中查看运行效果)
那么我们可以让子容器 view 的 tap 事件只派发一次吗?
片 5
答案肯定是可以的。可以使用 catch 绑定事件函数。catch 与 bind 的作用相同,与 bind 不同的是,catch 会阻止事件向上冒泡,catch是在事件的捕获阶段监听事件的。
从示例中看到,与前面代码只有一处不同,就是将子容器的 bindtap 改为了 catchtap,这样单击子容器组件,便不会输出两次了(见上面代码)。
(可以从视频中查看运行效果)
片 6
hover-start-time 是按住后,多久出现点击态,hover-stay-time 是手指松开后,点击态保留多长时间,单位均是毫秒。没有特殊说明,微信小程序中所有属性中的时间单位都是毫秒。
这两个属性的设置,说明在 view 容器组件内部,有代码掐表做了定时。当 touchstart 事件发生时,开始计时,到达 hover-start-time 时,应用 hover-class 样式;当 touchstart 结束,即 touchend 事件发生时,开始 hover-stay-time 倒计时,时间到,则移除 hover-class 样式。
设置 hover-start-time 属性,是为了方便开发者控制 hover-class 样式出现的时机。在测试中发现,但凡在 view 上单击一下,很正常的速度单击,不需要悬停,也会出现 hover-class 样式的应用。50ms 是它的默认时间,这是一个极短的时间,但是在计算机的微观世界里却是一个极长的时间,这个时间已经足以包裹一次系统单击事件。
单击事件不是一个点事件,它是一个跨度一定时间段的物理事件。我们以 mac 系统为例,系统设置里有一个地方可以改变单击事件的跟踪速度(见上面图例)。 改变这个跟踪速度后,在微信开发者工具模拟器中的 tap 事件也会受影响。如果我们把跟踪速度,调整到快的一侧,单击时只是轻轻点按,系统是不会触发单击事件的。
片 7
现在我们看一下本节课开始提到的问题。
我们知道,当延迟超过 100 毫秒时,用户就会感觉到界面明显的卡顿。但是在移动设备上,特别在苹果的 Safari 浏览器上,我们不得不忍受 300 毫秒的延时。
这是为什么呢?苹果创始人乔本斯 2007 年在 iPhone 发布会上演示过这样一个功能,对于一个 Safari 浏览器网页,在内容区快速双击,苹果会帮助我们准确定位到文章的主体内容,并将其放大(见上面图例)。
这个功能很酷,但它是有代价的。
如果用户不小心,在双击时击到了一个链接,这让软件怎么处理呢?是马上跳转,还是等待用户的另一个单击,以判断是不是双击事件呢?
苹果采用的是第二种方式,所有 Safafi 中的链接都要延迟 300 毫秒,观察用户有没有发出第二个单击事件,如果没有,再跳转链接。这导致苹果手机中的 HTML5 页面里单击反应都比较迟钝。
但是微信小程序没有这个问题,hover-start-time 的默认时间是 50ms,只需要 50ms 甚至更短就可以触发单击事件,微信小程序已经迈过了 300 毫秒迟延的限制。
如果有人问你,使用微信小程序开发产品,相比 HTML5 开发有什么优势?没有单击延迟,就是在体验上一个很大的优势。
在这里有一个作业留给大家思考:hover-start-time 这个属性的值,它的默认值是50ms,那么最小可以设置为多少呢?设置为 1ms 可以吗,为什么?相关问题在之前的课程中提到过。
片 8
下面我们看一下 hover-class这个属性的应用。我们可以基于 hover-class 这个属性实现按钮。
示例中的三个按钮,均是基于 button 组件改造的。button 是组件,同时实际上也是容器,所以可以把 button 当成 view 使用,在 button 上面也可以应用 hover-class 属性,虽然它的属性文档里没有标明,也可以使用。 这三个按钮主要使用了三个 hover-class 样式。
片 9
我们看看这三个类样式都有什么作用。
第一个样式,.btn 是普通的自定义按钮样式。flex 与 align-items 是为了实现文本与图标的横向对齐,这是 flex 布局方面的内容,稍后有详细介绍。#b2b2b2 这个颜色值,是符合微信设计规范的按钮边框色,#f2f2f2 是按钮背景色。(见上面代码)
第二个样式,transform 使圆形按钮在单击时缩小 0.05。按钮单击时微微缩小,这是从 Flash 交互时代传承下来的体验技巧,包括 0.05 这个数值当时在交互中也是经常用到的。(见上面代码)
第三个样式,#b2b2b2 颜色值做为边框色,以它的 rgba 格式的 20%透明形式(rgba(175, 175, 175, .2)),将它作为方形按钮按下状态的内阴影颜色,这也是符合微信颜色设计规范的。box-shadow 这个样式,用于定义组件的内阴影。 (见上面代码)
(可以从视频中查看运行效果)
现在我们看一下作业。
上节课我们留的作业是:在官方的 rich-text 组件中,如果节点有不支持的 HTML 属性,节点及子节点都会被移除。那么相同的 nodes 节点数据,如果改用 parser 组件渲染,可以渲染出来吗?
答案基本也是不行的。因为我们从源码中看到,parser 自定义组件的功能也是有限的,对于它本身不能渲染的标签,在内部也是交给 rich-text 去渲染的。所以如果有 rich-text 不支持的节点,交给 parser 也一样不行。
这节课我们还有一个作业:hover-start-time 这个属性的值,最小可以设置为多少?设置为 1 毫秒可以吗,为什么?如果你知道答案,欢迎在评论区留言。
好,这节课我们就讲到这里,这节课主要介绍了容器组件 view,以及它的一些重要的属性,了解了在苹果手机网页上,为什么有 300 毫秒延迟。下节课我们接着介绍容器组件view,并开始学习 flex 布局。
2020 年 5 月 16 日