大家好,我是卡颂。
都说中国人考究中庸之道,中国人造的框架考究么?
本文会从原理层面解说Vue
是如何在运行时与编译时之间放弃中庸的均衡。
UI = fn(state)
简直所有前端框架工作原理都能用如下公式概括:
UI = fn(state)
UI
(视图)能够通过state
(状态)通过fn
(框架)计算得出。
然而具体原理上,框架之间却千差万别。
能够依照更新粒度将他们分为三类:
- 树级更新
- 组件级更新
- 节点级更新
更新粒度没有优劣之分,只是对应不同的实现
接下来咱们简略理解下不同粒度更新形式的实现原理。
假如有如下组件树,其中Cpn
是一个自定义组件,内部结构为ul>li*2
:
咱们心愿将Cpn
内的一个li
更新为黄色:
树级更新
树级更新的框架会再生成一棵残缺虚构DOM树,生成过程中与之前的虚构DOM树对应节点进行比拟:
找到变动的节点后,执行对应DOM
操作。
树级更新框架的特点是:
- 依赖虚构DOM
- 不关怀触发更新的节点(因为会通过虚构DOM的全树比照找到他)
采纳这种更新形式最有名的框架就是React
。
组件级更新
下面的例子,如果是组件级更新框架。
会找到触发更新节点所在组件,生成该组件的虚构DOM树(而不是全树的虚构DOM树),生成过程中与该组件之前的虚构DOM树对应节点进行比拟:
找到变动的节点后,执行对应DOM
操作。
组件级更新框架的特点是:
- 依赖虚构DOM
- 关怀触发更新的节点(虚构DOM的比照会作用于该节点所在组件)
采纳这种更新形式最有名的框架就是Vue
。
节点级更新
如果是节点级更新框架,在编译时会依据状态变动对应的DOM变动间接生成对应办法,当状态扭转后间接调用对应办法。
下面的例子,在编译时会关联color
状态与changeColor
办法:
function changeColor(newColor) { li.style.color = newColor;}
当扭转color
状态后间接调用changeColor
办法更新li
对应DOM
。
节点级更新框架的特点是:
- 不依赖虚构DOM,依赖预编译(建设状态与扭转
DOM
的办法之间的分割) - 关怀触发更新的节点(节点状态与更新办法一一对应)
采纳这种更新形式最有名的框架就是Svelte
。
中庸的Vue3
Vue
作为组件级更新代表,更新粒度介于树级与节点级之间。那到底是两头偏左呢,还是两头偏右呢?
Vue3
说:
我要重复横跳,两边我都要
Vue3
中蕴含三种树状构造:
形容视图的树 -> 虚构DOM树 -> 实在DOM树
其中形容视图的树官网举荐应用模版语法,但也能应用JSX
。
不论是哪种形式,最终都会转化为虚构DOM树。
当应用JSX
时,Vue3
领有了React
运行时的灵活性,此时的Vue3
能够看作是加强版React + Mobx
当应用模版语法,Vue3
引入了预编译技术。此时能够将Vue3
的工作流程细化为四步:
形容视图的树 -> VNode树 -> Block数组 -> 实在DOM树
其中VNode树
就是惯例意义的虚构DOM树,Block数组
则为VNode树中对状态有依赖,会变动的那局部VNode
组成的数组。
比方,对于如下模版语法:
<template> <section> <div>i am</div> <p>{{name}}</p> </section></template>
section
与div
不蕴含状态,不会变动,所以会转化为VNode
,然而没有对应Block
。
p
蕴含状态name
,会转化为VNode
与Block
。
当该template
所在组件触发name
状态变动,之前须要顺次创立section
、div
、p
的VNode
并进行比拟。
有了预编译技术后只须要遍历Block数组
进行比拟。
用上文的例子即只须要比照一个li
节点:
在这种状况下,尽管是应用虚构DOM的组件级更新框架,然而曾经很靠近节点级更新框架了。
总结
本文按更新粒度介绍了三种不同类型的框架,以及Vue3
在抉择JSX
与模版语法
时在灵活性与更新粒度间的灵便变动。
能够说是很合乎中庸之道了。
有人会问,应用Vue3
的用户大部分都能承受模版语法,为什么不间接摈弃虚构DOM,应用预编译技术,实现真正的节点级更新?
一方面,虚构DOM使框架脱离具体的视图层,更不便跨端渲染。
另一方面,Vue2
社区生态积攒了大量基于虚构DOM的库。
如果是你,在这种状况下会作何抉择呢?