Vue 插槽(slot)使用

7/19/2020 Vue

# 介绍

还是老规矩放上官方文档:官方文档 slot (opens new window)

# 内容插槽

这是最基础的插槽

定义两个组件 parent.vuechildren.vue
然后在 parent.vue 组件中引用 children.vue 组件

第 4 行中。就是把值插入插槽中,如果对应组件并没有插槽,则不会渲染中间的内容




 









<!-- home.vue -->
<template>
  <children>
    Hello Word
    <ul>
      <li>0</li>
      <li>1</li>
      <li>2</li>
      <li>3</li>
    </ul>
  </children>
</template>
1
2
3
4
5
6
7
8
9
10
11
12

第 4 行中,就是定义了一个插槽




 



<!-- children.vue -->
<template>
  <a href="#">
    <slot>这是默认值</slot>
  </a>
</template>
1
2
3
4
5
6

插槽中可以使用的内容

  • 插入普通文本
  • 插入 HTML
  • 插入新的组件
  • 使用 {{}} 插入动态数据

插槽默认值

上面的例子中,子组件的 <slot> 中有一段文本这段文本就是默认值,他和插槽一样,可以是任意的内容
如果在引入该组件没有为插槽赋值时,默认值就会被渲染出来

基本上所有的内容都可以插入到插槽中,并没有限制。当然,父组件的插槽中的数据依旧是来自父组件的,并不是来自子组件的

# 具名插槽

上面的是默认插槽,有可能一个复杂的组件中需要有多个插槽的位置,就可以使用具名插槽






 




 




 




<!-- children -->
<template>
  <div>
    <header>
      <!-- 我们希望把页头放这里 -->
      <slot name="header"></slot>
    </header>

    <main>
      <!-- 我们希望把主要内容放这里 -->
      <slot></slot>
    </main>

    <footer>
      <!-- 我们希望把页脚放这里 -->
      <slot name="footer"></slot>
    </footer>
  </div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • 使用 name 属性定义插槽的名称。如果没有 name,默认就是 default
  • 插槽是可以重复定义的,在子组件中,同名的插槽也会重复渲染

具名插槽的使用

<template>
  <children>
    <template v-slot:footer>
      <p>Here some contact info</p>
    </template>
    <template #header> 这是头部信息 </template>
    <p>Here some contact info</p>
  </children>
</template>
1
2
3
4
5
6
7
8
9
  • 使用插槽的时候,默认插槽可以不指定 v-slot
  • 我们也可以使用新语法:#slot name 来使用插槽
  • 使用 v-slot 来使用插槽
  • 插槽的声明顺序并不会影响渲染顺序,渲染顺序又组件的插槽位置决定

# 作用域插槽

所有的插槽渲染都是有作用域的,插槽在哪个页面上渲染,作用域就在当前的页面(无法访问子组件的值)

那如果我们还是想展示子组件里面的值怎么办?
注意是父组件展示子组件的值
我们把需要传递的内容绑到 <slot> 上,然后在父组件中用 v-slot 设置一个值来定义我们提供插槽的名字:

子组件:



 
















<!-- children -->
<div>
  <slot :userInfo="user">{{user.name}}</slot>
</div>

<script>
  export default {
    //定义内容
    data() {
      return {
        user: {
          name: 'Jioho',
          age: 22
        }
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

在父组件中使用:
slotProps 名称是自定义的,可以指定默认插槽的数据名称

<!-- home.vue -->
<div>
  <children v-slot:default="slotProps">
    我是:{{ slotProps.user.name }}
  </children>
</div>
1
2
3
4
5
6

注意

默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:

<template>
  <children v-slot="slotProps">
    {{ slotProps.user.firstName }}
    <template v-slot:other="otherSlotProps">
      <!-- slotProps 将不会显示在这里 -->
    </template>
  </children>
</template>
1
2
3
4
5
6
7
8

多插槽和作用域

  • 子组件
<template>
  <div>
    <span>
      <slot v-bind:userData="user" name="header">
        {{ user.msg }}
      </slot>
      <slot v-bind:hobbyData="hobby" name="footer">
        {{ hobby.fruit }}
      </slot>
    </span>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        user: {
          firstName: 'gerace',
          lastName: 'haLi'
        },
        hobby: {
          fruit: 'apple',
          color: 'blue'
        }
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  • 父组件
<template>
  <myslot>
    <template v-slot:header="slotProps">
      {{ slotProps.userData.firstName }}
    </template>
    <template v-slot:footer="slotProps">
      {{ slotProps.hobbyData.fruit }}
    </template>
  </myslot>
</template>
1
2
3
4
5
6
7
8
9
10

结合上面所说的,使用 # 和使用 es6 的解构赋值。父组件可以写成如下写法:

<template>
  <myslot>
    <template #header="{userData}">
      {{ userData.firstName }}
    </template>
    <template #footer="{hobbyData}">
      {{ hobbyData.fruit }}
    </template>
  </myslot>
</template>
1
2
3
4
5
6
7
8
9
10
Last Updated: 5/9/2021, 10:45:03 PM