前言
首先,这篇文章肯定对我们的日常开发和代码完全没有任何帮助,写这篇文章纯属是为了自己的脑残,花了那么多时间去寻根究底找个慰藉。
之前在阅读diff源码时候经常会出现一个 cloneIfMounted 和 normalizeVNode 这俩东西,当时查阅了一下资料,可能晚上写的也只是初始化 vnode 啥的,没有细究,但是在研究 patch 时候的,这兄弟又出现了,然后手贱就点进去看了看,发现有一个 cloneVNode,顿时有了些疑惑,这个 cloneVNode 到底是做啥的呢。
浪费时间中
说到 clone ,我直接想到了 render,毕竟肯定是存在的东西才能克隆嘛。然后找到 h 函数。
function h(type, propsOrChildren, children) {
const l = arguments.length;
if (l === 2) {
if (shared.isObject(propsOrChildren) && !shared.isArray(propsOrChildren)) {
// single vnode without props
if (isVNode(propsOrChildren)) {
return createVNode(type, null, [propsOrChildren]);
}
// props without children
return createVNode(type, propsOrChildren);
}
else {
// omit props
return createVNode(type, null, propsOrChildren);
}
}
else {
if (l > 3) {
children = Array.prototype.slice.call(arguments, 2);
}
else if (l === 3 && isVNode(children)) {
children = [children];
}
return createVNode(type, propsOrChildren, children);
}
}
看了看,果不其然跟 clone 半毛钱关系没有。没办法,只能去源码中 console 一下,看看到底什么样的 vnode 会需要被 clone。
<template>
<div>
<div>i am a static div</div>
<div>i am a static div {{number}}</div>
<button @click="handleChangeNum">{{ number }} 修改按钮</button>
</div>
</template>
写了个最简单的例子, number 初始为 111,点击 +1。
开始的时候,并没有出现 log 信息,在点击了按钮以后,我就看到了光。
其实当这个 log 出来的时候,我就基本可以确定,这应该跟 vue3 中的静态 dom 优化有关系了。
再回过头看,其实刚刚在 normalizeVNode 的函数,也有了打印信息。
可以看到 children 有3个,但是 dynamicChilren 只有2个,少的那个就是被 clone 的那个纯文本的 div。
疑惑解开,但是你以为到这里就结束了吗?
no,因为之前 h 函数中的时候,我们发现都是重新 createVNode 的,并没有看到 clone 呀,那 h 函数中,是怎么进行优化的呢。
继续浪费时间中
继续写了个子组件 helloworld 来验证我这个猜想。
export default {
name: 'HelloWorld',
props: ['number'],
render() {
return h(
'div',
{
class: 'home'
},
[
this.number + '222222',
h('div', 'lalalala')
]
)
}
}
大致就是这样,刚刚的父组件中引入了 helloworld ,然后父组件中点击按钮更新 number 会触发子组件的 render,接下来又是看图说话了。
首先,会发现 dynamicChildren 变成了 null,然后发现 lalalala 并没有被 clone。
<template>
<div class="home">
{{number + '2222'}}
<div>
lalalahahaha
</div>
</div>
</template>
然后把 render 改为 template 写法,继续看图说话。
dynamicChildren 再度出现,同时在更新时, lalalahahaha 被 clone 了。
再继续浪费时间中
本来写到这里应该就停了,但是一想到都到这了,不如就继续吧。
研究下我们使用 template 写的 html,会被解析成啥样子。
hosted_1 就是 helloworld 的父 div, hoisted_2 就是固定文本 lalalahahaha,上面的就是 1112222 了,好家伙,果然跟自己写 h 完全不一样,涉及一些 openBlock,createBlock 这些素未蒙面的函数了。
再看看用自己的 render 函数写的打印情况,平平无奇,不能说是十分相似,只能说是一毛一样。
结语
本文到这里结束了。
不是真的结束,是我想结束了,因为又看到了 patchBlockChildren 和 patchChildren,简单来说,就是我自己看看就行了,写出来的话也没多大意思,会让本就枯燥无味的文字,雪上加霜。
虽然我整明白了 cloneVNode 是用来干什么的,但是,感觉并没有什么卵用,得到的结论是啥呢。
我们自己不要用 render,老老实实写 template 就好了?