插槽

1.2k 词

插槽#

默认插槽#

作用:让组件内部的一些结构支持自定义
需求:在页面中显示一个对话框,封装为一个组件
组件的内容部分,不希望写死,希望能在使用时自定义提示内容

插槽基本语法#

  1. 组件内需要定制的结构部分,改用<slot></slot>占位
  2. 使用组件时,<MyDialog></MyDialog>标签内部,传入结构替换slot

例:
MyDialog.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div class="dialog">
<div class="dialog-header">
<h3>友情提示</h3>
<span class="close">x</span>
</div>
<div class="dialog-content">
<!-- 在需要定制的位置使用slot占位 -->
<slot></slot>
</div>
<div class="dialog-footer">
<button>取消</button>
<button>确认</button>
</div>
</div>
</template>

App.vue:

1
2
3
4
5
6
7
<!-- 在使用组件时,在组件标签中插入定制内容 -->
<MyDialog>您确认要退出本系统吗</MyDialog>
<MyDialog>
<div>
<span>确认操作吗</span>
</div>
</MyDialog>

后备内容(默认值)#

通过插槽完成了内容的定制,传什么就显示什么
但若不传,则是空白
为了避免这类情况,可以给插槽设置默认显示内容
插槽后备内容:封装组件时,可以为预留的<slot>插槽提供后备内容

  • 语法:直接在<slot>标签内,放置内容,则会作为默认显示
1
<slot>默认文本内容</slot>
  • 效果:外部使用组件时,不传递内容,则插槽显示默认内容,若外部使用组件时传递了内容,则<slot>整体会被替换掉

具名插槽#

当一个组件内有多处结构,需要从外部传入标签进行定制时,默认插槽就没法用了,它只支持一个定制的位置
此时需要用到具名插槽
具名插槽语法:

  1. 多个slot使用name属性区分名字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div class="dialog">
<div class="dialog-header">
<!-- 在需要定制的位置使用slot占位 -->
<!-- 有多处需要定制的,用name区分 -->
<slot name="head"></slot>
</div>

<div class="dialog-content">
<slot name="content">默认内容</slot>
</div>
<div class="dialog-footer">
<slot name="footer"></slot>
</div>
</div>
</template>
  1. temlate配合v-slot:插槽名来分发对应标签,v-slot:插槽名可以简写为#插槽名
1
2
3
4
5
6
7
8
9
10
11
12
13
<MyDialog>
<!-- 具名插槽使用时,需要用template包裹需要定向分发的结构 -->
<template v-slot:head>
<div>大标题</div>
</template>
<template v-slot:content>
<div>内容</div>
</template>
<template #footer>
<button>确认</button>
<button>取消</button>
</template>
</MyDialog>

一旦插槽起了名字,就是具名插槽,只支持定向分发

作用域插槽#

插槽分类:默认插槽(组件内定制一处结构),具名插槽(组件内定制多处结构)
作用域插槽是插槽的一个传参语法
作用:定义slot插槽时,是可以传值的,给插槽上绑定数据,将来使用组件时可以用
场景:封装表格组件

  1. 父传子,动态渲染表格内容
  2. 利用默认插槽,定制操作列
  3. 删除或查看操作,都需要用到当前项的 id,属于组件内部的数据

通过作用域插槽传值绑定进而使用
基本使用步骤:

  1. slot标签,以添加属性的方式传值
1
<slot :id="item.id" msg="测试文本"></slot>
  1. 所有添加的属性,都会被收集到一个对象中
1
{ "id": 3, "msg": "测试文本" }
  1. template中,通过#插槽名='obj'接收,默认插槽名为default
1
2
3
4
5
<MyTable :list="list">
<template #default="obj">
<button @click="del(obj.id)">删除</button>
</template>
</MyTable>

完整代码:
App.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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<template>
<div>
<MyTable :data="list">
<template #default="obj">
<button @click="del(obj.stu.id)">删除</button>
</template>
</MyTable>

<MyTable v-bind:data="list2">
<!-- 若知道传递的数据,甚至可以直接解构 -->
<template #default="{ stu }">
<button @click="show(stu)">查看</button>
</template>
</MyTable>
</div>
</template>

<script>
import MyTable from './components/MyTable.vue';
export default {
data() {
return {
list: [
{ id: 1, name: '张小花', age: 18 },
{ id: 2, name: '孙大明', age: 19 },
{ id: 3, name: '刘德忠', age: 17 },
],
list2: [
{ id: 1, name: '赵小云', age: 18 },
{ id: 2, name: '刘蓓蓓', age: 19 },
{ id: 3, name: '姜肖泰', age: 17 },
],
};
},
components: {
MyTable,
},
methods: {
del(id) {
console.log(id);
this.list = this.list.filter(item => item.id !== id);
},
show(stu) {
alert(`姓名:${stu.name},年龄:${stu.age}`);
},
},
};
</script>

MyTable.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
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<template>
<table class="my-table">
<thead>
<tr>
<th>序号</th>
<th>姓名</th>
<th>年纪</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in data" :key="item.id">
<td>{{ index + 1 }}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<td>
<!-- 给slot标签以添加属性的方式传值 -->
<slot :stu="item" msg="测试文本"></slot>
<!-- 所有的属性都会被添加到一个对象中 -->
<!--
{
stu:{id:1,name:'xxx',age:18},
msg:'测试文本'
}
-->
</td>
</tr>
</tbody>
</table>
</template>

<script>
export default {
props: {
data: Array,
},
};
</script>

<style scoped>
.my-table {
width: 450px;
text-align: center;
border: 1px solid #ccc;
font-size: 24px;
margin: 30px auto;
}
.my-table thead {
background-color: #1f74ff;
color: #fff;
}
.my-table thead th {
font-weight: normal;
}
.my-table thead tr {
line-height: 40px;
}
.my-table th,
.my-table td {
border-bottom: 1px solid #ccc;
border-right: 1px solid #ccc;
}
.my-table td:last-child {
border-right: none;
}
.my-table tr:last-child td {
border-bottom: none;
}
.my-table button {
width: 65px;
height: 35px;
font-size: 18px;
border: 1px solid #ccc;
outline: none;
border-radius: 3px;
cursor: pointer;
background-color: #ffffff;
margin-left: 5px;
}
</style>