当下的前端同学对 React 与 Vue 的组件化开发想必不会陌生,RN 与 Weex 的跨界也常为我们所津津乐道。UI 框架在实现这样的跨端渲染时需要做哪些工作,其技术方案能否借鉴乃至应用到我们自己的项目中呢?这就是本文所希望分享的主题。
概念简介
什么是跨端渲染呢?这里的「端」其实并不局限在传统的 PC 端和移动端,而是抽象的 渲染层 (Renderer) 。渲染层并不局限在浏览器 DOM 和移动端的原生 UI 控件,连静态文件乃至虚拟现实等环境,都可以是你的渲染层。这并不只是个美好的愿景,在 8102 年的今天,除了 React 社区到 .docx
/ .pdf
的渲染层以外,Facebook 甚至还基于 Three.js 实现了到 VR 的渲染层,即 ReactVR。现在回顾 React 的 Learn Once, Write Anywhere 口号,实际上强调的就是它对各种不同渲染层的支持:
为什么不直接使用渲染层的 API 呢?跨端开发的一个痛点,就在于各种不同渲染层的学习、使用与维护成本。而不管是 React 的 JSX 还是 Vue 的 .vue
单文件组件,都能有效地解耦 UI 组件,提高开发效率与代码维护性。从而很自然地,我们就会希望使用这样的组件化方式来实现我们对渲染层的控制了。
在开始介绍如何为 React / Vue 适配不同渲染层之前,我们不妨回顾一下它们在老本行 DOM 中执行时的基本层次结构。比如我们都知道,在浏览器中使用 React 时,我们一般需要分别导入 react
与 react-dom
两个不同的 package,这时前端项目的整体结构可以用下图简略地表示:
很多前端同学熟悉的 UI 库、高阶组件、状态管理等内容,实际上都位于图中封装后「基于 React 实现」的最顶层,连接 React 与 DOM 的 React DOM 一层则显得有些默默无闻。而在 Vue 2.x 中,这种结构是类似的。不过 Vue 目前并未实现 React 这样的拆分,其简化的基本结构如下图所示:
如何将它们这个为 DOM 设计的架构迁移到不同的渲染层呢?下文中会依次介绍这些实现方案:
- 基于 React 16 Reconciler 的适配方式
- 基于 Vue EventBus 的非侵入式适配方式
- 基于 Vue Mixin 的适配方式
- 基于 Vue Platform 定制的适配方式
React Reconciler 适配
之所以首先介绍 React,是因为它已经提供了成型的接口供适配之用。在 React 16 标志性的 Fiber 架构中, react-reconciler
模块将基于 fiber 的 reconciliation 实现封装为了单独的一层。这个模块与我们定制渲染层的需求有什么关系呢?它的威力在于, 只要我们为 Reconciler 提供了宿主渲染环境的配置,那么 React 就能无缝地渲染到这个环境 。这时我们的运行时结构如下图所示:
上图中我们所需要实现的核心模块即为 Adapter ,这是将 React 能力扩展到新渲染环境的桥梁。如何实现这样的适配呢?
我们以适配著名的 WebGL 渲染库 PIXI.js 为例,简要介绍这一机制如何工作。首先,我们所实现的适配层,其最终的使用形式应当如下:
import * as PIXI from &