• 10.2 具有后备内容的插槽

    10.2 具有后备内容的插槽

    有时为一个插槽设置具体的后备 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染。查看源码发现后备内容插槽的逻辑也很好理解。

    1. var child = {
    2. template: `<div class="child"><slot>后备内容</slot></div>`
    3. }
    4. var vm = new Vue({
    5. el: '#app',
    6. components: {
    7. child
    8. },
    9. template: `<div id="app"><child></child></div>`
    10. })
    11. // 父没有插槽内容,子的slot会渲染后备内容
    12. <div class="child">后备内容</div>

    父组件没有需要分发的内容,子组件会默认显示插槽里面的内容。源码中的不同体现在下面的几点。

    1. 父组件渲染过程由于没有需要分发的子节点,所以不再需要拥有componentOptions.children属性来记录内容。
    2. 因此子组件也拿不到$slot属性的内容.
    3. 子组件的render函数最后在_t函数参数会携带第二个参数,该参数以数组的形式传入slot插槽的后备内容。例with(this){return _c('div',{staticClass:"child"},[_t("default",[_v("test")])],2)}
    4. 渲染子Vnode会执行renderSlot(即:_t)函数时,第二个参数fallback有值,且this.$slots没值,vnode会直接返回后备内容作为渲染对象。
    1. function renderSlot (
    2. name,
    3. fallback, // slot插槽后备内容(针对后备内容)
    4. props, // 子传给父的值(作用域插槽)
    5. bindObject
    6. ){
    7. if() {
    8. ···
    9. }else{
    10. //fallback为后备内容
    11. // 如果父占位符组件没有插槽内容,this.$slots不会有值,此时vnode节点为后备内容节点。
    12. nodes = this.$slots[name] || fallback;
    13. }
    14. }

    最终,在父组件没有提供内容时,slot的后备内容被渲染。

    有了这些基础,我们再来看官网给的一条规则。

    父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

    父组件模板的内容在父组件编译阶段就确定了,并且保存在componentOptions属性中,而子组件有自身初始化init的过程,这个过程同样会进行子作用域的模板编译,因此两部分内容是相对独立的。