1.所有的组件树中,如果 VNode 是组件或含有组件的 slot,那么 VNode 必须唯一。 所以下面的 两个示例都是错误的。这该怎么理解

第一个错误栗子:

<div id='app'>
    <ele></ele>
<div>
var Child = {
    render: function (createElement) {
        return createElement("p", "text");
    }
};
Vue.component("ele", {
    render: function (createElement) {
        var ChildNode = createElement(Child);
        return createElement("div", [
            ChildNode ,
            ChildNode 
        ]);
    }
})

第二个错误栗子:

<div id='app'>
    <ele>
        <div>
            <Child></Child>
        </div>
    </ele>
<div>
Vue.component("Child", {
    render: function (createElement) {
        return createElement("p", "text");
    }
});
Vue.component("ele", {
    render: function (createElement) {
        var ChildNode = createElement(Child);
        return createElement("div", [
            this.$slots.default,
            this.$slots.default
        ])
    }
})

这两个栗子说期待渲染两个Child组件,也就是两个<p>text</p>节点,实际上只渲染出一个,因为VNode受到约束。

可是我试过可以渲染出两个节点也就是<p>text</p>,不知道它渲染出的一个是怎么说的


···回复:

渲染是没问题的, 但这会破坏后续的更新.

如下这个例子: 在第一次点击时, 两个 p 都可以更新, 但第二次以后就只有第二个 p 的内容会被更新.

var Child = {
  props: {
    text: {},
  },
  render: function(createElement) {
    return createElement('p', this.text);
  },
};

Vue.component('ele', {
  data() {
    return {
      text: 'test',
    };
  },
  render: function(createElement) {
    var ChildNode = createElement(Child, {
      props: { text: this.text },
      nativeOn: {
        click: () => {
          this.text = 'clicked ' + new Date();
        },
      },
    });
    return createElement('div', [ChildNode, ChildNode]);
  },
});

new Vue({
  el: '#app',

  template: `
    <div id='app'>
      <ele />
    </div>
  `,
});

这是由于 vue 当前实现会将 vnode 会与其渲染出来的 dom 元素进行一对一关联, 当你同一个 vnode 渲染两次后, vnode 最终只会与最后一个渲染出来的 dom 元素关联, 所以在 patch 阶段只有最后一个 dom 可以被更新.

这实质上是 vue 的缺陷, github 已经有相关 issue 请求 vue 支持 vnode 复用, 因为这种使用方式一来很符合直觉, 二来存在实际的使用场景.

— 更新
v2.5.18 开始 vue 支持 vnode 复用了.

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Scroll Up