vue3中插槽的使用

[TOC]

插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签,父组件填充的内容称为插槽内容

  • 子组件不提供插槽时,父组件填充失效
  • 父组件无填充时,<slot></slot>中的备用内容会启用生效
  • 父级模板里的所有内容都是在父级作用域中编译的,子模板里的所有内容都是在子作用域中编译的,互不影响

匿名插槽

又名默认插槽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- my-button子组件定义 -->
<template>
<button>
<slot>SUBMIT BTN</slot>
</button>
</template>

<!-- 父组件调用my-button -->
<my-button>
提交按钮
</my-button>

<!-- 父组件页面渲染为 -->
<button>
提交按钮
</button>

具名插槽

当有多个插槽时,插槽增加了name属性来正确渲染对应的部分,父组件需要使用<template></template>。可以认为匿名插槽是特殊的具名插槽

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!-- my-layout子组件定义 -->
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<!-- 其实就是<slot name="default"></slot> -->
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>

<!-- 父组件调用my-layout -->
<my-layout>
<!-- 填充内容顺序无关 -->
<template v-slot:footer>
<p>我来组成脚丫子</p>
</template>

<!-- v-slot:header可以简写为#header -->
<template v-slot:header>
<h1>我来组成头部</h1>
</template>

<!-- v-slot:default可以忽略不写 -->
<template v-slot:default>
<p>我来组成身体</p>
</template>
</my-layout>

<!-- 父组件页面渲染为 -->
<div>
<header>
<h1>我来组成头部</h1>
</header>
<main>
<p>我来组成身体</p>
</main>
<footer>
<p>我来组成脚丫子</p>
</footer>
</div>

作用域插槽

让父级插槽内容能够访问子组件数据,数据从子组件往父组件流动。子组件通过插槽prop(任意个数)来绑定数据,父组件通过带值(命名随意)的v-slot来获取子组件的数据。

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!-- todo-list子组件定义 -->
app.component('todo-list', {
data() {
return {
items: [
{ "thing1":"阅读", "thing2":"看电视" },
{ "thing1":"背单词", "thing2":"玩游戏" }
]
}
},
template: `
<ul>
<li v-for="(item, index) in items">
<!-- data即插槽prop,绑定item,index也是插槽prop,绑定index,备用内容为item.thing1 -->
<slot :data="item" :index="index">{{ item.thing1 }}</slot>
</li>
</ul>
`
})

<!-- 正常用法:父组件调用todo-list -->
<todo-list>
<!-- 这里default就是具名插槽的用法,slotProps来接收子组件数据,命名随意 -->
<template v-slot:default="slotProps">
<i class="fas fa-check"></i>
<span class="green">{{ slotProps.index }} + ' - ' + {{ slotProps.data.thing2 }}</span>
</template>
</todo-list>

<!-- 特殊用法:只有默认插槽时,v-slot可以写在组件上 -->
<todo-list v-slot:default="slotProps">
<template>
<i class="fas fa-check"></i>
<span class="green">{{ slotProps.index }} + ' - ' + {{ slotProps.data.thing2 }}</span>
</template>
</todo-list>

<!-- 特殊用法:v-slot有解构的用法 -->
<todo-list v-slot:default="{index, data}">
<template>
<i class="fas fa-check"></i>
<span class="green">{{ index }} + ' - ' + {{ data.thing2 }}</span>
</template>
</todo-list>

<!-- 父组件页面渲染为 -->
<ul>
<li>
<i class="fas fa-check"></i>
<span class="green">0 - 看电视</span>
</li>
<li>
<i class="fas fa-check"></i>
<span class="green">1 - 玩游戏</span>
</li>
</ul>