Vue3-08

插槽 Slot

组件能够接受任意类型的 JavaScript 片段作为 props,包括基本类型、对象、数组、函数等等。但是在一些场景中要让组件接受的内容更加灵活,比如说我们想要在组件中插入一些 HTML 片段,或者是一些组件,这时候就需要用到插槽。

插槽的基本使用

在 Vue2 中,我们可以通过在组件中使用 <slot> 标签来实现插槽的功能,比如下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
<template>
<div>
<slot></slot>
</div>
</template>

<script>
export default {
name: 'App',
}
</script>

在这个例子中,我们在组件中使用了 <slot> 标签,这个标签就是一个插槽,它的作用是在组件中插入一些内容,这些内容可以是 HTML 片段,也可以是其他的组件,比如下面这个例子:

ParentComponent.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div>
<ChildComponent>
<h1>这是一个标题</h1>
<p>这是一个段落</p>
</ChildComponent>
</div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
name: 'ParentComponent',
components: {
ChildComponent,
},
}
</script>

ChildComponent.vue

1
2
3
4
5
<template>
<div>
<slot></slot>
</div>
</template>
  • 参考:彻底搞懂slot插槽,图文详解

渲染作用域

插槽内容可以访问到父组件的数据作用域,这意味着我们可以在父组件中定义一些数据,然后在插槽中使用这些数据。

延用上一个例子的 ChildComponent 组件,我们在父组件中定义一个 title 数据,然后在插槽中使用这个数据,比如下面这个例子:

ParentComponent.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<div>
<ChildComponent>
<h1>{{ title }}</h1>
<p>这是一个段落</p>
</ChildComponent>
</div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
name: 'ParentComponent',
components: {
ChildComponent,
},
data() {
return {
title: '这是一个标题',
}
},
}
</script>

<slot> 标签中的内容可以访问到父组件的数据作用域,这意味着我们可以在父组件中定义一些数据,然后在插槽中使用这些数据。

具名插槽

在 Vue2 中,我们可以通过在 <slot> 标签上添加一个 name 属性来实现插槽的命名,比如下面这个例子:

ParentComponent.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div>
<ChildComponent>
<template v-slot:header>
<h1>这是一个标题</h1>
</template>
<template v-slot:footer>
<p>这是一个段落</p>
</template>
</ChildComponent>
</div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
name: 'ParentComponent',
components: {
ChildComponent,
},
}
</script>

ChildComponent.vue

1
2
3
4
5
6
<template>
<div>
<slot name="header"></slot>
<slot name="footer"></slot>
</div>
</template>

默认内容

在 Vue2 中,我们可以在 <slot> 标签中添加一些默认的内容,这些内容会在父组件中没有提供插槽内容的时候显示出来,比如下面这个例子:

ChildComponent.vue

1
2
3
4
5
6
<template>
<div>
<slot name="header"></slot>
<slot>这是一个默认的内容</slot>
</div>
</template>

插槽中的数据传递

某些场景下插槽内容可能要同时使用父组件中的数据和子组件中的数据,这时可以像对组件传递 props 一样,向插槽的出口添加 attribute 属性,比如下面这个例子:

ParentComponent.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div>
<ChildComponent>
<template v-slot:header="slotProps">
<h1>{{ slotProps.title }}</h1>
</template>
</ChildComponent>
</div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
name: 'ParentComponent',
components: {
ChildComponent,
},
}
</script>

ChildComponent.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>
<slot name="header" :title="title"></slot>
</div>
</template>

<script>
export default {
name: 'ChildComponent',
data() {
return {
title: '这是一个标题',
}
},
}
</script>

v-slot 指令可以接收一个参数,这个参数是一个对象,这个对象中包含了一些属性,其中 slotProps 属性是一个对象,这个对象中包含了插槽中的数据,我们可以通过这个对象来访问插槽中的数据。

此外,v-slot 指令可以使用缩写—# 来代替。