大家好,我是卡颂。
最近中午没胃口,找来 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 教程,感兴趣的敌人能够去看看。如果有能力,记得去反对正版哦。