阅读 388

vue中的cloneVNode

前言

首先,这篇文章肯定对我们的日常开发和代码完全没有任何帮助,写这篇文章纯属是为了自己的脑残,花了那么多时间去寻根究底找个慰藉。

之前在阅读diff源码时候经常会出现一个 cloneIfMountednormalizeVNode 这俩东西,当时查阅了一下资料,可能晚上写的也只是初始化 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 信息,在点击了按钮以后,我就看到了光。

image.png

其实当这个 log 出来的时候,我就基本可以确定,这应该跟 vue3 中的静态 dom 优化有关系了。

再回过头看,其实刚刚在 normalizeVNode 的函数,也有了打印信息。

image.png

可以看到 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,接下来又是看图说话了。

image.png

首先,会发现 dynamicChildren 变成了 null,然后发现 lalalala 并没有被 clone

<template>
  <div class="home">
    {{number + '2222'}}
    <div>
      lalalahahaha
    </div>
  </div>
</template>
复制代码

然后把 render 改为 template 写法,继续看图说话。

image.png

image.png

dynamicChildren 再度出现,同时在更新时, lalalahahahaclone 了。

再继续浪费时间中

本来写到这里应该就停了,但是一想到都到这了,不如就继续吧。

研究下我们使用 template 写的 html,会被解析成啥样子。

image.png

hosted_1 就是 helloworld 的父 divhoisted_2 就是固定文本 lalalahahaha,上面的就是 1112222 了,好家伙,果然跟自己写 h 完全不一样,涉及一些 openBlockcreateBlock 这些素未蒙面的函数了。

再看看用自己的 render 函数写的打印情况,平平无奇,不能说是十分相似,只能说是一毛一样。 image.png

结语

本文到这里结束了。

不是真的结束,是我想结束了,因为又看到了 patchBlockChildrenpatchChildren,简单来说,就是我自己看看就行了,写出来的话也没多大意思,会让本就枯燥无味的文字,雪上加霜。

虽然我整明白了 cloneVNode 是用来干什么的,但是,感觉并没有什么卵用,得到的结论是啥呢。

我们自己不要用 render,老老实实写 template 就好了?

文章分类
前端
文章标签