mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-24 20:00:37 +00:00
90 lines
5.7 KiB
Markdown
90 lines
5.7 KiB
Markdown
# 多端融合方案
|
||
|
||
## SwfitUI
|
||
|
||
SwiftUI 自亮相以来,全网就在讨论其与 React、Flutter 之间的关系。
|
||
|
||
首先是与 Flutter 的对比,Flutter 的思路是从 0 开始,即语言、基础库、渲染引擎、排版引擎即框架本身全部由自己实现,其渲染引擎 Skia 只需要操作系统为其提供一个 GL Context 便可以完成所有图形渲染,这使得其跨平台性变得十分强大,到目前为止 Windows、Linux、macOS、Fuchsia 都已经得到了 Flutter 官方的支持。
|
||
|
||
这种做法我认为有利有弊,首先好处是所有平台下行为一致,不管是滚动视图、Material Design 控件还是模糊效果这些在其他平台没有的都得到了全平台的支持,开发者并不需要为这些去做平台间的适配,反观 React Native… 当然缺点也是存在的,Flutter 这种做法类似于游戏引擎,平台提供的 UI 特性它一概不用,因此 Flutter View 与原生视图的交互就没有那么容易了,同时新的 Dart 语言貌似也不是非常受社区和开发者喜爱。
|
||
|
||
SwiftUI 没有像 Flutter 那样从头再来,这个全新的框架依旧使用了 UIKit、AppKit 等作为基础。但它并不是一个 UIKit 的声明式封装
|
||
|
||
许多基础组件,像 Text、Button 等都并不是直接使用 UILabel、UIButton 而是一个名为 DisplayList.ViewUpdater.Platform.CGDrawingView 的 UIView 子类。它们使用了自定义绘制,但又集成于 UIKit 的环境中,因此我猜测 SwiftUI 只提供了组件的自定义渲染和布局引擎,它使用到的底层技术还是 Core Animation、Core Graphics、Core Text 等。使用自定义绘制去实现组件可以理解成为跨平台提供便利,毕竟一个按钮还要区分 UIButton、NSButton 来实现未免有些麻烦。但是部分复杂的控件还是采用了 UIKit 中已有的类,比如 UISwitch 等。由于未脱离 UIKit 体系,嵌入一个 UIView 非常容易,你不需要搞什么外部纹理(Flutter 需要),因为它们的上下文是同一个,坐标系也是同一个。
|
||
|
||
所以我认为 SwiftUI 更加类似 React Native,使用系统框架提供的组件,只不过绘制和布局可以自己来实现,这在 SwiftUI 之前也有相关的框架这样实践的,比如 Yoga、ComponentKit 等。
|
||
|
||
|
||
SwiftUI 是声明式的 UI 开发方式。关于声明式和命令式的介绍可以查看这篇[博文](https://github.com/FantasticLBP/knowledge-kit/blob/master/第七部分%20设计模式/7.1.md)。声明式开发框架 SwiftUI、React、Flutter、Vue 等都具备下面的特点。
|
||
|
||
- 使用各自的 DSL 来描述UI 该长什么样子(样式模版),而不是一句句代码描述来告诉系统该如何一步步构建 UI
|
||
- 声明所需要的数据部分
|
||
- 框架内部通过模版和数据部分,负责渲染绘制
|
||
- 数据发送变动
|
||
- 框架根据最新的数据和样式模版计算出最新的样式声明
|
||
- 最新的样式声明和之前的样式声明比较,计算出差值。系统重新绘制
|
||
|
||
```Swift
|
||
@State var name: String = "Tom"
|
||
var body: some View {
|
||
Text("Hello \(name)")
|
||
}
|
||
```
|
||
|
||
在 SwiftUI 中, view 是由纯数据结构描述的。因此这些数据的创建和差分计算都不会带来太多的性能开销。
|
||
|
||
## React && React Native
|
||
|
||
先谈谈 React 吧。React 的优秀的地方在于:Virtual DOM、JSX、单向数据流等等。但是谈谈 React 这些框架为什么可以做 Web 也可以做跨端解决方案 RN。传统的 Web 开发是基于命令式编程的方式,监听事件、发起请求、操作 DOM、刷新页面。想想看,每次数据变动了都需要刷新 DOM,然后用户就可以在浏览器上看到了最新的数据,DOM 的操作是很耗费资源的。怎么理解这句话,其实 DOM 对象本身就是一个 JS 对象,所以 JS 对于 JS 对象的操作来说性能耗费基本不用考虑,微乎其微。但是 DOM 每次变动到真实 UI 的渲染是非常耗费性能的(触发浏览器的布局和绘制)。至于浏览器的布局重绘原理我会新开文章进行讨论和总结,可以先看看文章底部的参考资料。
|
||
|
||
在 React 中使用数据(state、props)+ 样式模版(JSX)的方式开发 UI。以下是 React 大致的工作原理
|
||
|
||
- 设置页面所需要的数据 State、props
|
||
- 创建页面的模版样式部分 JSX
|
||
- 根据数据和样式模版生成 Virtual DOM
|
||
- 页面首次渲染的时候先根据 Virtual DOM 生成真实的 UI
|
||
- 数据变动(setState)结合「批更新策略」
|
||
- 根据变动后的数据和模版样式生成新的 Virtual DOM
|
||
- 根据 Diff 算法计算变动的 Virtual DOM 部分
|
||
- 根据变动的 Virtual DOM 部分去绘制 UI
|
||
|
||
什么是 Virtual DOM?
|
||
|
||
Virtual DOM 就是一个 JS 对象,用来描述真实的 DOM。看看下面的例子
|
||
|
||
```HTML
|
||
<ol id='ol-list'>
|
||
<li class='item'>Item 1</li>
|
||
<li class='item'>Item 2</li>
|
||
<li class='item'>Item 3</li>
|
||
</ol>
|
||
```
|
||
|
||
转换为 Virtual DOM
|
||
|
||
```Javascript
|
||
var olElement = {
|
||
tagName: 'ol',
|
||
props: {
|
||
id: 'ol-list'
|
||
},
|
||
children: [
|
||
{tagName: 'li', props: {class: 'item'}, children: ['Item 1']},
|
||
{tagName: 'li', props: {class: 'item'}, children: ['Item 2']},
|
||
{tagName: 'li', props: {class: 'item'}, children: ['Item 3']}
|
||
]
|
||
}
|
||
```
|
||
|
||
所以 Virtual DOM 抽象出来后就很方便了,在 Web 端可以去渲染到真实的 DOM;在 Native 端可以去映射到 Native UI 组件上。所以 React 有了 Virtual DOM 便可以在 Web 端和 Native 端大展拳脚。
|
||
|
||
|
||
|
||
## 参考资料
|
||
|
||
- [浏览器的布局绘制与DOM操作](https://blog.csdn.net/sinat_32434539/article/details/77894009)
|
||
- [前端必读:浏览器内部工作原理](https://www.cnblogs.com/rainy-shurun/p/5603686.html)
|
||
- [深度理解 Virtual DOM](https://www.cnblogs.com/wubaiqing/p/6726429.html)
|
||
|
||
|