this.$children 表现得好像是反应性的

this.$children is behaving as if it were reactive

官方docthis.$children没有反应,

The direct child components of the current instance. Note there’s no order guarantee for $children, and it is not reactive...

因此,任何更改都不应触发任何重新渲染。 [this.$children api 已从 vuejs v3 中删除,因此它仅适用于 v2.x。]

我发现这很有趣... https://codepen.io/tatimblin/pen/oWKdjR

上面沙箱中的代码是使用 slot & this.$childen api 实现的选项卡 UI 的演示。 最初 tabs 组件持有对 this.$children 数组的引用,这是它的日志:

有趣的是,tabisActive 道具正在使用该数组进行更改,但它反映在每个组件中,导致重新渲染.. 我不确定这里发生了什么……也许我遗漏了什么。

模板:

<div id="root" class="container">

  <tabs>
    <tab name="Services" :selected="true">
      <h1>What we do</h1>
    </tab>
    <tab name="Pricing">
      <h1>How much we do it for</h1>
    </tab>
    <tab name="About Us">
      <h1>Why we do it</h1>
    </tab>
  </tabs>

</div>

JS:

Vue.component('tabs', {
    template: `
        <div>
            <div class="tabs">
              <ul>
                <li v-for="tab in tabs" :class="{ 'is-active': tab.isActive }">
                    <a :href="tab.href" @click="selectTab(tab)">{{ tab.name }}</a>
                </li>
              </ul>
            </div>

            <div class="tabs-details">
                <slot></slot>
            </div>
        </div>
    `,
    
    data() {
        return {tabs: [] };
    },
    
    created() {
        
        this.tabs = this.$children;
        
    },
    methods: {
        selectTab(selectedTab) {
            this.tabs.forEach(tab => {
                tab.isActive = (tab.name == selectedTab.name); 
               // this is how the isActive prop is changed, using this.$children
            });
        }
    }
});

Vue.component('tab', {
    
    template: `

        <div v-show="isActive"><slot></slot></div>

    `,
    
    props: {
        name: { required: true },
        selected: { default: false}
    },
    
    data() {
        
        return {
            isActive: false
        };
        
    },
    
    computed: {
        
        href() {
            return '#' + this.name.toLowerCase().replace(/ /g, '-');
        }
    },
    
    mounted() {
        
        this.isActive = this.selected;
        
    }
});

new Vue({
    el: '#root'
});

子元素是反应式的,因为它们本身就是 Vue 组件,除了 tabs 父元素之外,它们已经具有全部的反应能力。

文档引用意味着内容本身不会反应。这种区别可能会更清楚一些。另一方面,如果插槽内容不是具有 isActive 属性 的组件,则 tabs 将无法正常工作,这形成了紧密耦合。它不能与原始 HTML 插槽内容一起正常工作,例如:

  <tabs>
    <div>
      Hi, I'm not a component
    </div>
  </tabs>