大概几集下饭剧时间就能懂的VUE3原理
source link: https://segmentfault.com/a/1190000040611431
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
大家好,我是卡颂。
最近中午没胃口,找来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官方推出了课程讲解
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
官方推出了,感兴趣的朋友可以去看看。如果有能力,记得去支持正版哦。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK