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的过程,这个过程同样会进行子作用域的模板编译,因此两部分内容是相对独立的。