原生组件、小程序与客户端通信原理、video、map、canvas、picker等运行原理

 原生组件

在内置组件中,有一些组件较为特殊,它们并不完全在Exparser的渲染体系下,而是由客户端原生参与组件的渲染,这类组件我们称为“原生组件”,这也是小程序Hybrid技术的一个应用。

1 原生组件运行机制

要介绍原生组件的运行机制,我们需要从一行代码看起。

代码清单展示一个地图组件

<map latitude="39.92" longtitude="116.46"></map>

在原生组件内部,其节点树非常简单,基本上可以认为只有一个div元素。上面这行代码在渲染层开始运行时,会经历以下几个步聚:

  1. 组件被创建,包括组件属性会依次赋值。
  2. 组件被插入到DOM树里,浏览器内核会立即计算布局,此时我们可以读取出组件相对页面的位置(x, y坐标)、宽高。
  3. 组件通知客户端,客户端在相同的位置上,根据宽高插入一块原生区域,之后客户端就在这块区域渲染界面(客户端就是主微信程序)
  4. 当位置或宽高发生变化时,组件会通知客户端做相应的调整

我们可以看出,原生组件在WebView这一层的渲染任务是很简单,只需要渲染一个占位元素,之后客户端在这块占位元素之上叠了一层原生界面。因此,原生组件的层级会比所有在WebView层渲染的普通组件要高。

​ 图 原生组件层级示意图

引入原生组件主要有3个好处:

  1. 扩展Web的能力。比如像输入框组件(input, textarea)有更好地控制键盘的能力。
  2. 体验更好,同时也减轻WebView的渲染工作。比如像地图组件(map)这类较复杂的组件,其渲染工作不占用WebView线程,而交给更高效的客户端原生处理。
  3. 绕过setData、数据通信和重渲染流程,使渲染性能更好。比如像画布组件(canvas)可直接用一套丰富的绘图接口进行绘制。

表 常用的几个原生组件

组件名 名称 是否有**context** 描述
video 视频 播放视频
map 地图 展示地图
canvas 画布 提供一个可以自由绘图的区域
picker 弹出式选择器 初始时没有界面,点击时弹出选择器

交互比较复杂的原生组件都会提供“context”,用于直接操作组件。以canvas为例,小程序提供了wx.createCanvasContext方法来创建canvas的context。这是一个可以用于操作canvas的对象,对象下提供了很多绘图的方法,如“setFillStyle”方法可以设置填充样式,“fillRect”方法用于绘制矩形(这些方法与HTML DOM Canvas兼容)。

代码清单 canvas组件context对象示例(WXML代码)

<canvas canvas-id="myCanvas"></canvas>

代码清单 canvas组件context对象示例(JS代码)

const ctx = wx.createCanvasContext('myCanvas')
ctx.setFillStyle('red')
ctx.fillRect(10, 10, 150, 75)
ctx.draw()

这段代码可以创建WXML中对应canvas节点的context,通过调用context中的方法,在画布上绘制一个矩形。

类似于canvas,video、map等原生组件都可以创建context,context中提供的方法非常丰富,这里就不一一列举了。

2 原生组件渲染限制

原生组件脱离在WebView渲染流程外,这带来了一些限制。最主要的限制是一些CSS样式无法应用于原生组件,例如,不能在父级节点使用overflow:hidden来裁剪原生组件的显示区域;不能使用transformrotate让原生组件产生旋转等。

开发者最为常见的问题是,原生组件会浮于页面其他组件之上(相当于拥有正无穷大的z-index值)使其它组件不能覆盖在原生组件上展示。想要解决这个问题,可以考虑使用cover-view和cover-image组件。这两个组件也是原生组件,同样是脱离WebView的渲染流程外,而原生组件之间的层级就可以按照一定的规则控制。


小程序与客户端通信原理

1 视图层组件

内置组件中有部分组件是利用到客户端原生提供的能力,这类组件基本都是前面描述的原生组件。既然需要客户端原生提供的能力,那就会涉及到视图层与客户端的交互通信。这层通信机制在 iOS 和安卓系统的实现方式并不一样,iOS 是利用了WKWebView 的提供 messageHandlers 特性,而在安卓则是往 WebView 的 window 对象注入一个原生方法,最终会封装成 WeiXinJSBridge 这样一个兼容层,主要提供了调用(invoke)和监听(on)这两种方法。

实际上,在视图层与客户端的交互通信中,开发者只是间接调用的,真正调用是在组件的内部实现中。开发者插入一个原生组件,一般而言,组件运行的时候被插入到 DOM 树中,会调用客户端接口,通知客户端在哪个位置渲染一块原生界面。在后续开发者更新组件属性时,同样地,也会调用客户端提供的更新接口来更新原生界面的某些部分。

2 逻辑层接口

逻辑层与客户端原生通信机制与渲染层类似,不同在于,iOS平台可以往JavaScripCore框架注入一个全局的原生方法,而安卓方面则是跟渲染层一致的。

同样地,开发者也是间接地调用到与客户端原生通信的底层接口。一般我们会对逻辑层接口做层封装后才暴露给开发者,封装的细节可能是统一入参、做些参数校验、兼容各平台或版本问题等等。

猜你喜欢

转载自blog.csdn.net/m0_58859743/article/details/125948899