Vue中的slot
# Vue 中的 slot 插槽
# 1 概述
# 1) 什么是 slot
slot 可以理解为预留了一个可替换的地方
游戏卡是可以插拔的, 插游戏卡的地方就是一个插槽
思考
游戏卡插槽有什么作用?
再比如, USB 接口也可以看成一个插槽
. 可以插入 U 盘, 硬盘, 鼠标, 键盘...
还有, CPU 槽, 内存槽. 他们的存在有什么共同点??
# 2) 为什么需要 slot
通过上面的例子, 我们可以看出
- 通过插不同的游戏卡, 可以玩不同的游戏
- 通过插不同的外设, 可以扩展电脑的功能
- 通过插不同型号的 CPU(i3/i5/i7/i9), 可以更换 CPU
所以, 插槽最主要的作用是提供扩展性
.
# 3) Vue 中的 slot
在 Vue 开发中, slot 主要应用在组件开发中, 通过在组件中预留 slot, 实现不同的功能
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<son></son>
</div>
<template id="tmp">
<div>我是子组件</div>
</template>
<script>
const vm = new Vue({
el: '#app',
components: {
son: {
template: '#tmp',
},
},
})
</script>
</body>
</html>
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
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
子组件的模板编译后, 会替换<son>
所在的地方
但是, 不管在<son>
中添加任何内容, 都不起作用~
<div id="app">
<son>
<!-- 在子组件里写的内容不会生效 -->
<h2>我是子组件的标题</h2>
</son>
</div>
1
2
3
4
5
6
2
3
4
5
6
这样, 子组件的可扩展性就很不好. 如果希望子组件中的内容可以替换怎么办??
在子组件中预留一个插槽
, 通过给子组件传递不同的内容来改变子组件
# 2 具名插槽
# 1) 作用
如果需要同时使用多个插槽, 就需要给插槽取名字.
就好比: 主板上同时有 CPU 槽和内存槽, 如何区分这两个插槽, 不至于把内存插到 CPU 中
当然, 现实中肯定不会, 但是程序中就需要使用名字区分开
# 2) 使用
- 在子组件中, 定义具名插槽
- 在引用子组件时, 通过
slot属性
指定要替换的插槽
<div id="app">
<son>
<div slot="cpu">我是CPU</div>
<div slot="memery">我是内存</div>
</son>
</div>
<template id="tmp">
<div>
<slot name="cpu"></slot>
<slot name="memery"></slot>
</div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
没有指定的内容会全部放到<slot>
中, 也就是默认插槽
<div id="app">
<son>
<div slot="cpu">我是CPU</div>
<div slot="memery">我是内存</div>
<hr />
<div>我是剩余的内容</div>
<p>我也是...</p>
</son>
</div>
<template id="tmp">
<div>
<slot name="cpu"></slot>
<slot name="memery"></slot>
<!-- slot其实也有名字, 名字是default -->
<slot></slot>
<slot name="default"></slot>
</div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 3 作用域插槽
# 1) 编译作用域
在 Vue 编译的过程中, 如果父子组件中定义的相同的状态
, 会不会冲突呢?
如果不会冲突, 具体访问的是哪个状态
呢
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button v-show="isShow">按钮</button>
<son></son>
</div>
<template id="tmp">
<div>
<h3>我是子组件</h3>
<button v-show="isShow">子组件按钮</button>
</div>
</template>
<script>
const vm = new Vue({
el: '#app',
data: {
isShow: false,
},
components: {
son: {
template: '#tmp',
data() {
return {
isShow: true,
}
},
},
},
})
</script>
</body>
</html>
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
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
父组件和子组件中都存在isShow
.
- 如果在父模板中使用 isShow, 访问的是父组件
data
中的值 - 如果在子模板中使用 isShow, 访问的是子组件
data
中的值
通过上述示例, 我们可以发现, 在父组件中是不能直接访问子组件中的状态的.
需求
- 在父模板中可定制子组件的内容
- 同时使用子组件中的数据
# 2) 为什么需要作用域插槽
为了解决上述问题, 引入了作用域插槽的概念, 其核心是在父模板中访问子组件的数据
示例
<div id="app">
<button v-show="isShow">按钮</button>
<!-- 通过v-slot指令找名字为default的插槽, 并指定prop对象对应default插槽 -->
<son v-slot:default="prop">
<!-- 通过prop对象访问show属性, 相当于访问了子组件的isShow -->
<button v-show="prop.show">子组件按钮</button>
</son>
</div>
<template id="tmp">
<div>
<h3>我是子组件</h3>
<!-- 在slot:default对象中, 定义自定义属性show -->
<slot :show="isShow"></slot>
</div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
其中, v-slot
可以使用#
简写
<!-- 通过v-slot指令找名字为default的插槽, 并指定prop对象对应default插槽 -->
<son #default="prop">
<!-- 通过prop对象访问show属性, 相当于访问了子组件的isShow -->
<button v-show="prop.show">子组件按钮</button>
</son>
1
2
3
4
5
2
3
4
5
通过同时有多个插槽, 需要借用<template>
语法
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button v-show="isShow">按钮</button>
<!-- 通过v-slot指令找名字为default的插槽, 并指定prop对象对应default插槽 -->
<son>
<template #default="prop">
<!-- 通过prop对象访问show属性, 相当于访问了子组件的isShow -->
<button v-show="prop.show">子组件按钮</button>
</template>
<template #left="left">
<h3>{{left.info.name}}</h3>
</template>
</son>
</div>
<template id="tmp">
<div>
<h3>我是子组件</h3>
<!-- 在slot:default对象中, 定义自定义属性show -->
<slot :show="isShow"></slot>
<slot name="left" :info="stu"></slot>
</div>
</template>
<script>
const vm = new Vue({
el: '#app',
data: {
isShow: false,
},
components: {
son: {
template: '#tmp',
data() {
return {
isShow: true,
stu: {
name: 'xiaoming',
age: 18,
},
}
},
},
},
})
</script>
</body>
</html>
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
57
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
57
#
如果觉得有帮助, 可以微信扫码, 请杰哥喝杯咖啡~
上次更新: 2021/09/03, 15:32:17