本文将向大家介绍 Remax 的实现原理,Remax 本身分为两个部分,remax
和 reamx-cli
,remax
提供运行时,remax-cli
提供构建功能,这里主要介绍运行时的部分。
Remax 的运行时本质是一个通过 react-reconciler
实现的一个小程序端的渲染器。关于 react-reconciler
和 React 渲染器相关的内容推荐观看这个视频,这里不再赘述。
大家知道,小程序对我们的代码屏蔽了 DOM,我们的代码运行在一个 worker 线程中,无法直接去操作视图层的 DOM。Remax 通过引入一层 VNode
,让 React 在 reconciliation 过程中不是直接去改变 DOM,而是更新 VNode
。
VNode
的基本结构如下:
interface VNode {
id: number;
container: Container;
children: VNode[];
mounted: boolean;
type: string | symbol;
props?: any;
parent: VNode | null;
text?: string;
appendChild(node: VNode): void;
removeChild(node: VNode): void;
insertBefore(newNode: VNode, referenceNode: VNode): void;
toJSON(): RawNode;
}
id
- 节点 id,这是一个自增的唯一 id,用于标识节点。container
- 类似 ReactDOM.render(<App />, document.getElementById('root')
中的第二个参数,Remax 中会把组件渲染到一个容器中,容器的作用是保存 VNode
的引用。children
- 子节点。mounted
- 标识节点是否已经显示到视图层上。type
- 节点的类型,也就是小程序中的基础组件,如:view
、text
等等。props
- 节点的属性。parent
- 父节点。text
- 文本节点上的文字。可以看到,VNode
也是一个树结构,我们在 VNode
上实现了类似 DOM
中的节点操作方法。在 React 的更新完成后,我们会调用节点上的 toJSON
方法,把这个 VNode
变成一个 JSON 对象。
举个例子,假设我们有这样一个页面组件:
import React from 'react';
import { View, Text } from 'remax/alipay';
const IndexPage = () => {
return (
<View className="greeting">
<Text>Hello Remax</Text>
</View>
);
};
export default IndexPage;
Remax 在渲染这个组件时,会把它渲染成如下的 VNode
结构:
{
"id": 0,
"type": "root",
"children": [
{
"id": 1,
"type": "view",
"props": {
"className": "greeting"
},
"children": [
{
"id": 2,
"type": "text",
"props": {},
"children": [
{
"type": "plain-text",
"text": "Hello Remax"
}
]
}
]
}
]
}
其中 root
节点是由 Remax 内部创建的,这个渲染出来的 VNode
数据就会成为小程序 Page
的 data
。
具体这部分的源码实现可以参考下面三个文件:
上面讲到我们的 React 组件最终会被渲染成一个我们称之为 VNode
的 JSON 对象,并且这个对象会作为小程序 Page
的 data
。现在我们要做的就是在小程序的模板里怎么把这个 data
给显示出来了。
我们在 remax-cli
构建我们的 Remax 代码时 生成一个页面模板显示这个 VNode
,这个模板大概是下面这个样子:
<block a:for="{{root.children}}" a:key="{{item.id}}">
<template is="{{'REMAX_TPL_' + item.type}}" data="{{item: item}}" />
</block>
<template name="REMAX_TPL_view">
<view class="{{item.props['className']}}">
<block a:for="{{item.children}}" key="{{item.id}}">
<template is="{{'REMAX_TPL_' + item.type}}" data="{{item: item}}" />
</block>
</view>
</template>
<template name="REMAX_TPL_text">
<text>
<block a:for="{{item.children}}" key="{{item.id}}">
<template is="{{'REMAX_TPL_' + item.type}}" data="{{item: item}}" />
</block>
</text>
</template>
<template name="REMAX_TPL_plain-text">
<block>{{item.text}}</block>
</template>
可以看到,我们会先去遍历根节点的子元素,再根据每个子元素的类型选择对应的模板来渲染子元素,然后在每个模板中我们又会去遍历当前元素的子元素,以此把整个节点树递归遍历出来。
深蓝互联成立于2013年,是一家物联网硬件开发及软件应用服务商,获得多次获得国家高新技术企业资质的企业。深蓝互联专注软硬件技术开发的专业性技术公司。我们从事软硬件开发十年,擅长SaaS 平台开发、APP小程序开发、软硬件结合开发,在视觉识别处理、数据架构、云计算、多线程高并发和集群、数据安全加密和防护方便有很深的技术积累。
我们拥有专业优秀的设计和技术团队,以极具创意的 UI 设计、精湛卓越的开发技术,专业的网络策划团队。公司多年来投入打造物联网SaaS平台,集成了公司研发的多款智能物联网终端(智能鲜米机、生鲜售货机、自助洗车机、小区电瓶车充电系统等)。
公司一直坚持以研发为导向,打造软硬件结合的物联网平台系统。将一直坚持提高开发的技术实力更好的为我们的客户服务!
文章来自深蓝互联http://www.szdbi.com/webxt/313.html转载请注明出处!