概述
触发依赖之后都会执行patch函数,它做了什么呢?
patch的作用是通过对比新旧虚拟dom,来更新dom。其中涉及到的知识点非常多,我们必须一步一步的分析。
h函数的使用
const h = (type, props, children) => {
return createVNode(type, props, children);
};
// 使用
h("div", {cc: 1132}, [
h("p", {aaa: 111}, "apiInject"),
h(ProviderOne, {aaa: 222})
]);
h(ProviderTwo); // ProviderTwo是一个组件
通过h函数的使用分析createVNode的三个参数:
type:1、html标签;2、一个组件。
props:是属性。1、如果type是标签,则props是标签的属性;2、如果type是组件,则props可以在其setup中接收;3、没有则是undefined。
children:1、字符串:文本子元素内容;2、数组:多个子元素,可以在里面用h函数。
createVNode:h函数的参数 => VNode
const createVNode = function (type, props, children) {
const vnode = {
el: null,
component: null,
key: props === null || props === void 0 ? void 0 : props.key,
type,
props: props || {},
children,
shapeFlag: getShapeFlag(type),
};
if (Array.isArray(children)) {
vnode.shapeFlag |= 16;
}
else if (typeof children === "string") {
vnode.shapeFlag |= 8;
}
normalizeChildren(vnode, children);
return vnode;
};
三个参数生产vnode
const vnode = {
el: null,
component: null,
key: props === null || props === void 0 ? void 0 : props.key,
type,
props: props || {},
children,
shapeFlag: getShapeFlag(type),
};
生成key
key:props中有key则用,无key则设为0;
生成shapeFlag
shapeFlag:设置一个标记:string:1;array:4
function getShapeFlag(type) {
return typeof type === "string"
? 1
: 4;
}
产生四种标记
- type是string(标签)、children是array:shapeFlag = 17
- type是string(标签 、children是string:shapeFlag = 9
- type是组件、children是array:shapeFlag = 20
- type是组件、children是string:shapeFlag = 12
if (Array.isArray(children)) {
vnode.shapeFlag |= 16;
} else if (typeof children === "string") {
vnode.shapeFlag |= 8;
}
执行normalizeChildren
满足typeof children === "object" shapeFlag分别是17、20
- 17 & 1 = 1
- 20 & 1 = 0 执行vnode.shapeFlag |= 32:shapeFlag=52
function normalizeChildren(vnode, children) {
if (typeof children === "object") {
if (vnode.shapeFlag & 1) ;
else {
vnode.shapeFlag |= 32;
}
}
}
最终结果
| type\children | string | array | undefined |
|---|---|---|---|
| 标签string | 9 | 17 | 1 |
| 组件object | 12 | 52 | 4 |
第一次调用patch
const render = (vnode, container) => {
patch(null, vnode, container);
};
patch源码
function patch(n1, n2, container = null, parentComponent = null) {
const { type, shapeFlag } = n2;
switch (type) {
case Text:
processText(n1, n2, container);
break;
case Fragment:
processFragment(n1, n2, container);
break;
default:
if (shapeFlag & 1) {
// console.log("处理 element");
processElement(n1, n2, container);
}
else if (shapeFlag & 4) {
// console.log("处理 component");
processComponent(n1, n2, container, parentComponent);
}
}
}
type:组件对象、标签名,所以先不考虑Text、Fragment
结合上面的表格,得出结论:
- 17、1、9(type是标签)会执行processElement(n1, n2, container)
- 4、12、52(type是组件)会执行processComponent(n1, n2, container, parentComponent);