从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计 (2)

既然小程序不能直接使用html标签来渲染页面,那它提供的如viewcover-view等内置组件是否意味着最终都转换为html提供的内置标签来渲染呢?答案当不是。我们来看如下代码:

<view> <map latitude=\'39.9088230000\' longitude=\'116.3974700000\' scale=\'16\' bindregionchange="onRegionChange"></map> <view catchtap="onTap">test</view> </view>

上面代码在开发者工具中最终渲染元素如下图:

从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计

可以看出,小程序提供的组件并没有最终转换为为html对应的标签来渲染,而是使用自定义的元素来渲染。这些内置组件都是由Exparser框架负责管理,它内置在小程序基础库中,为小程序的各种组件提供基础的支持。

Exparser框架基于Shadow DOM模型,模型上与WebComponents的ShadowDOM高度相似,具体可以参考官网组件系统。
内置组件的命名规范都是以wx-开头的,外部引用内置组件如view,最终会调用底层的wx-view组件;Exparser的view组件创建方式如下:

从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计

4、小程序可以操作dom吗?数据驱动

小程序为了管控与安全,提供一个JavaScript沙箱环境来运行JavaScript代码,js代码不能访问任何浏览器相关的接口,那就意味着js是不能操作dom和bom的,否则可能报错。小程序实现沙箱环境呢?即通过将业务逻辑封装到一个局部环境中,局部环境修改dom和bom的相关api指向。具体封装形式如下:

从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计

那么问题来了,小程序是怎么给业务代码加上以上封装的呢?其实很简单,在小程序开发者工具中有一个后台服务,访问小程序的每个模块的path时,后台服务会调用wrapSourceCodeInDefine方法将请求的JS文件的内容分别包裹在define域中,方法的代码如下图所示:

从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计

这里的define是小程序底层实现模块化的方法之一,还有一个是require方法;通过define来定义一个模块,require来引用一个define定义的模块。从上面小程序对业务模块代码的封装可以看出:

define定义的模块对传递了跟浏览器相关的接口同名的API,如window、document、localStroage等等
可能有人会说通过Function(\'return this\')()来访问全局作用域window对象,但是小程序堵死了这条路,重写了Functioneval重置为undefined。例如下图:

从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计

require在引用模块时只传递require、module、exports三个参数,那么其他参数值就为undefined,不能在业务代码中访问这些接口

可以看看require定义的源码:

从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计

在实际的微信环境,业务逻辑层运行在JSCore中,其没有浏览器相关的信息,访问dom无从谈起;但是小程序开发者工具使用webview来运行业务逻辑代码,它有dom相关接口;所以通过上面沙箱环境来统一使js无法操作dom。

业务代码无法访问dom,怎么实现页面动态更新呢?

答案就是采用类vue这种MVVM框架的数据驱动思想,即让视图状态和视图绑定在一起,状态变更时,视图也能自动变更,这样就不用直接操作dom。

视图的动态更新具体是采用virtual dom技术实现,virtual DOM相信大家都已有了解,大概是这么个过程如下图:

从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计

实际处理可以简单描述如下:

用JS对象模拟DOM树 -> 比较两棵虚拟DOM树的差异 -> 把差异应用到真正的DOM树上。

其中,virtual dom是通过内置的wcc可以将wxml转换为js对象形式,以此来表示DOM树结构。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyxpyj.html