大家好,我是卡颂。
最近中午没胃口,找来VUE
源码相干视频来当下饭剧。几顿饭上来,人胖了,VUE
也整明确了。
这篇文章为你带来一份VUE3
原理速成指南。
模块划分
如果咱们用VUE的模版语法定义:
<div>hello</div>
最终VUE
会帮咱们在浏览器中渲染对应的DOM节点
。
这之间对这段节点的形容会经验4次变动,横跨编译时与运行时:
模版语法在编译时会被编译器转化为render函数,相似:
render(h) { return h('div', 'hello');}
在运行时,render函数执行后返回的h函数的执行后果就是VNode
(也就是虚构DOM
),相似:
{ tag: "div", children: [ { text: "Hello" } ]}
最终,VUE
依据VNode
的信息,在浏览器渲染对应DOM
。
那么,是谁在驱动这一流程?
mount和patch
组件有两种不同的渲染逻辑:首次渲染和更新。
首次渲染意味着从无到有,比方上文的VNode
:
{ tag: "div", children: [ { text: "Hello" } ]}
可能对应如下DOM
操作:
const node = document.createElement(VNode.tag);node.textConent = 'Hello';contanerDOM.appendChild(node);
更新则须要比照更新前后VNode
,对变动局部执行DOM
操作。
比方,以上VNode
如果变为:
{ tag: "div", children: [ { // text扭转 text: "world" } ]}
则最终执行:
node.textContent = 'world';
VUE
的首次渲染对应mount
模块,更新对应patch
模块。
所以,render函数
执行后返回VNode
,依据状况不同,会走mount
或patch
的渲染逻辑:
如果想深刻虚构DOM
相干常识,举荐浏览snabbdom源码。这是个优良的虚构DOM库,VUE2
的虚构DOM
局部就是fork
这个库革新的。
那么是谁在什么机会调用了render函数
呢?
响应式更新
在VUE
中,状态变动会实时反映到视图上,比方:
<div @click="count++">{{count}}</div>
点击div
后:
- 触发点击事件,
count
变动 count
变动触发回调,回调中更新视图
以后咱们曾经晓得第二步是因为触发了如下流程:
所以只须要建设count
变动到执行render函数
的分割即可。
具体来说,咱们心愿实现reactive
及watchEffect
:
// 定义状态const state = reactive({count: 0});// 监听状态变动watchEffect(() => { console.log(state.count);})// 扭转状态state.count++;
reactive
定义状态。
watchEffect
依据回调执行的状况决定监听哪些状态。
比方watchEffect
回调执行了console.log(state.count);
,他就会监听state
的变动。
当执行state.count++;
,因为watchEffect
监听了state
的变动,则其回调会触发,打印state.count
。
这就是Reactivity
模块。
VUE官网推出了VUE3响应式原理课程解说Reactivity
的实现,这是B站链接。如果经济容许,请反对正版
当实现了Reactivity
模块,咱们就能将组件状态与后续流程串联起来。
方才讲过,render函数
是编译器依据模版语法生成的。在面对带状态的模版语法时,比方上文的count
:
<div @click="count++">{{count}}</div>
render函数
内的count
是响应式的(即:count
理论是reactive({count: 0})
)。
那么就能用watchEffect
监听count
的变动。
所以,在利用初始化时,会有相似逻辑:
let isMounted = false;let oldVNode;watchEffect(() => { if (!isMounted) { // mount逻辑 // 调用render函数 oldVNode = component.render(); // mount mount(oldVNode); } else { // patch逻辑 // 调用render函数 newVNode = component.render(); patch(oldVNode, newVNode); oldVNode = newVNode; }})
其中component.render()
(render函数的执行)达到上文监听状态变动的成果:
// 监听状态变动watchEffect(() => { console.log(state.count);})
所以,该组件内任何状态变动都会触发watchEffect
的执行,watchEffect
回调内会触发后续流程。
总结
VUE3
按原理大体能够划分为:
- mount
- patch
- 编译器
- Reactivity
VUE
官网推出了实现繁难VUE3教程,感兴趣的敌人能够去看看。如果有能力,记得去反对正版哦。