# 插槽slot

# 插槽内容

  • 自定义组件元素内容可以覆盖子组件内的slot元素,元素内容可以是另一个组件。
  • 如果子组件没有slot传入的元素内容不会被使用
<navigation-link url="/profile">Your Profile</navigation-link>

<!-- 模板内容 -->
<a 
  :href="url"
  class="nav-link"
>
  <slot></slot>
</a>

# 编译作用域

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

<navigation-link url="/profile">
  Clicking here will send you to: {{ url }}
  <!--
  这里的 `url` 会是 undefined,因为 "/profile" 是
  _传递给_ <navigation-link> 的而不是
  在 <navigation-link> 组件*内部*定义的。
  -->
</navigation-link>

# slot默认替代值(后背内容)

<button type="submit">
  <slot>Submit</slot>
</button>

<!-- 如果使用该模板,没传入元素内容,那么slot会渲染为Submit -->
<!-- 如果提供了内容就会使用提供的内容 -->

# 具名插槽

一个子组件内有多个slot插槽时,会通过name属性指定插槽名称,这种插槽就是具名插槽。

  • 2.6.0+ 写法 v-slot:header
  • 废弃的写法 slot="header"
// template 里面,没命名的slot元素,隐藏的名字为 "default"
Vue.component('page-layout', {
  template: `
    <div>
      <header>
        <slot name="header">header插槽默认内容</slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer">footer插槽默认内容</slot>
      </footer>
    </div>
  `
})

使用该组件,用template元素包裹,v-slot:插槽名,向对应的具名插槽提供内容。注意 v-slot 只能添加在一个template元素上。

<page-layout>
  <template v-slot:header>
    <h1>Title</h1>
  </template>

  <p> 一个段落在main content</p>
  <p>And another one.</p>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</page-layout>

# 作用域插槽

  • 2.6.0+ 写法 v-slot:header="slotProps"
  • 废弃的写法 slot="header" slot-scope="slotProps"
<!-- user在父组件里渲染,无法访问user,需要要子组件的插槽把值传出来 -->
<current-user>
  {{ user.firstName }}
</current-user>

<script>
Vue.component('current-user', {
  template: `
    <span>
      <slot>{{ user.lastName }}</slot>
    </span>
  `
})
</script>


<!-- 
  1.为了让user在父级的插槽内容中可用,可以将user作为slot元素的一个特性绑定上去
  2.组件元素使用v-solt:default="slotProps"就可以访问值了。
-->
<current-user v-slot:default="slotProps">
  {{ slotProps.user.firstName }}
</current-user>

<script>
Vue.component('current-user', {
  template: `
    <span>
      <slot v-bind:user="user">{{ user.lastName }}</slot>
    </span>
  `
  // 具名插槽 <slot name="footer">footer插槽默认内容</slot>
})
</script>

# 仅有一个插槽时的简写

如果仅有一个插槽 v-slot:default可以简写为v-slot,但如果有两个或两个以上的插槽,就不能使用简写了。

<!-- 单个插槽可简写-->
<current-user v-slot="slotProps"> 
  {{ slotProps.user.firstName }}
</current-user>

<!-- 多个插槽 -->
<current-user>
  <template v-slot:default="slotProps"> <!-- <template v-slot:header> -->
    {{ slotProps.user.firstName }}
  </template>

  <template v-slot:other="otherSlotProps">
    ...
  </template>
</current-user>

# 解构插槽prop

插槽内部传出来的变量,赋值给组件元素时,可以使用结构赋值

  <!-- 
    template: `
      <span>
        <slot v-bind:user="user">{{ user.lastName }}</slot>
      </span>
    ` 
  -->

<!-- 一般写法-->
<current-user v-slot="slotProps"> 
  {{ slotProps.user.firstName }}
</current-user>

<!-- 解构写法 -->
<current-user v-slot="{ user }">
  {{ user.firstName }}
</current-user>

<!-- 解构写法,将user重命名为person -->
<current-user v-slot="{ user: person }">
  {{ user.firstName }}
</current-user>

<!-- 解构写法,设置默认值,如果插槽prop的值为undefined  -->
<current-user v-slot="{ user = { firstName: 'Guest' } }">
  {{ user.firstName }}
</current-user>

# 动态插槽名

动态指令参数也可以用在v-slot上,来定义动态的插槽名

<!-- 一般的动态指令参数: -->
<input v-bind:[attrname]="dosomething" v-model="name">

<!-- 动态指令参数-->
<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>

# 具名插槽的缩写(2.6.0+)

v-slot:可以简写为#,和其他指令一样,只有在有参数的时候才可用

<template v-slot:header>
  <h1>Title</h1>
</template>

可以简写为: 
<template #header>
  <h1>Title</h1>
</template>

<!-- 不可用 -->
<current-user #="slotProps"> 
  {{ slotProps.user.firstName }}
</current-user>

<!-- 如果想使用可以给一个默认的值 -->
<current-user #default="slotProps"> 
  {{ slotProps.user.firstName }}
</current-user>
上次更新: 2020/10/29 22:59:19