理解 Vue slot

@sakila1012 2018-12-07 03:40:16发表于 sakila1012/blog

写在前面

总是遇到 slot,但看官网上的描述,一直没有看懂,所以有必要好好看看,深入理解。

官网上,slot 作用是内容分发。看下例子

<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <children>
    <span>我是父组件放在子组件中,没有 slot 我不会显示</span>
  </children>
</div>

...

var vm = new Vue({
  el: '#app',
  components: {
    children: {
      templete: '<button>我是一个没有 slot 的子组件模板</button>'
    }
  }
})

这里并没有显示 children 组件中的 span 内容,如果想显示 span 怎么办,那就是使用在组件模板中使用 slot 进行 span 内容的一个分发:

<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <children>
    <span>我是父组件放在子组件中,没有 slot 我不会显示</span>
  </children>
</div>

...

var vm = new Vue({
  el: "#app",
  components: {
    children: {
      templete: '<button><slot></slot>我是一个没有 slot 的子组件模板</button>'
    }
  }
})

说明 span 的内容作为 button 的子标签已经显示 OK,那么问题来了,如果我们有好几个 slot 怎么办,父组件可能同时会在子组件中放置多个 span 标签,比如下面这种:

<div id="app">
  <children>
    <span>我是父组件放在子组件中的 slot 1111111111111</span>
    <span>我是父组件放在子组件中的 slot 2222222222222</span>
  </children>
</div>

在子组件中需要选择性的表示第一个 span 还是第二个 span,怎么办,直接这样试试:

var vm = new Vue({
  el: '#app',
  components: {
    children: {
      templete: '<button><slot></slot>我是一个没有 slot 的子组件模板 <slot></slot>'
    }
  }
})

以上写法肯定是错误,这样写的话相当于没有区分两个 span,这样在 slot 分发的时候会将两个 span 标签内容当做一个标签合并插入 2 处 slot 位置那里,正确的做法是为 slot 指定 name 属性:

<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <children>
    <span slot="1">我是一个父组件放在自组件中的 slot 1111111111</span>
    <span slot="2">我是一个父组件放在自组件中的 slot 2222222222</span>
  </children>
</div>

...

var vm = new Vue({
  el: '#app',
  components: {
    children: {
      templete:  '<button><slot name="1"></slot>我是一个没有 slot 的子组件模板 <slot name="2"></slot></buttom>'
    }
  }
})

以上才可以正确输出如下

对于以下情景我们可以再测试下

1、子组件模板中指定 name 属性的 slot 不存在

<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <children>
    <span slot="1">我是一个父组件放在自组件中的 slot 1111111111</span>
    <span slot="2">我是一个父组件放在自组件中的 slot 2222222222</span>
  </children>
</div>

...

var vm = new Vue({
  el: '#app',
  components: {
    children: {
      templete:  '<button><slot name="3"></slot>我是一个没有 slot 的子组件模板 </buttom>'
    }
  }
})

当在 children 内找不到匹配的 slot 时,相当于该 slot 无效,即以上两个 span 均不会显示

2、子组件模板中指定 name 属性的 slot 存在,但是父组件注入的另一个 slot 没有使用的情况:

<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <children>
    <span slot="1">我是一个父组件放在自组件中的 slot 1111111111</span>
    <span slot="2">我是一个父组件放在自组件中的 slot 2222222222</span>
  </children>
</div>

...

var vm = new Vue({
  el: '#app',
  components: {
    children: {
      templete:  '<button><slot name="1"></slot>我是一个没有 slot 的子组件模板</buttom>'
    }
  }
})

同样地,相当于该具名 slot 没有生命而已,即 slot 等于 2 的 span 不会显示

以上我们提供了两种 slot,没有指定 name 属性的 slot 为“单个slot”,指定了 name 属性的 slot 称作为 “具名 slot”,具名 slot 会查找相应的 slot 属性相同的父组件内容进行匹配。

参考1