✨✨ 欢迎大家来到景天科技苑✨✨
🎈🎈 养成好习惯,先赞后看哦~🎈🎈
🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,Golang开发,云原生开发,前后端框架,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S集群搭建与管理,linux,shell脚本等实操经验,网站搭建,数据库等分享。所属的专栏:前端零基础,实战进阶教学
景天的主页:景天科技苑
Vue插槽
插槽(Slot)是Vue.js中一个非常重要的概念,它极大地提高了组件的复用性和灵活性。通过插槽,我们可以自定义组件的内容,使其能够适应不同的场景。本文将结合实际案例,详细介绍Vue中插槽的基本用法、类型以及高级技巧。
一、插槽的基本概念
在Vue中,子组件的模板可以定义多个插槽(包括默认插槽和具名插槽等),而父组件在引用子组件时,可以根据需要有选择性地为这些插槽插入内容。如果父组件没有为某个插槽提供内容,那么子组件的模板中该插槽的位置将显示为该插槽的默认内容(如果有的话),或者简单地留空。
二、默认插槽
默认插槽是插槽家族中最简单的使用方式,它没有指定名称,用于接收父组件传递的未明确指定插槽名称的内容。
1. 基本语法
在子组件中使用<slot></slot>
定义默认插槽的位置,父组件中直接放在子组件标签内的内容会被渲染到该位置。
2. 代码示例
子组件(DefaultSlotChild.vue):
<template>
<div class="child">
<h2>我是子组件的标题</h2>
<!-- 默认插槽 -->
<slot></slot>
</div>
</template>
父组件:
<template>
<div>
<DefaultSlotChild>
<!-- 这里的内容会被渲染到子组件的默认插槽中 -->
<p>这是来自父组件的默认插槽内容1</p>
<p>这是来自父组件的默认插槽内容2</p>
</DefaultSlotChild>
</div>
</template>
<script>
import DefaultSlotChild from './DefaultSlotChild.vue';
export default {
components: {
DefaultSlotChild
}
}
</script>
在这个例子中,父组件传递了两个段落标签到子组件的默认插槽中,这两个段落标签会被渲染到子组件模板的<slot></slot>
位置。
3. 后备内容(默认值)
如果父组件没有为默认插槽提供内容,子组件的模板中该插槽的位置可以显示后备内容(默认内容)。
<template>
<div class="child">
<h2>我是子组件的标题</h2>
<!-- 默认插槽,带有后备内容 -->
<slot>这是默认插槽的后备内容</slot>
</div>
</template>
当父组件没有为默认插槽提供内容时,后备内容“这是默认插槽的后备内容”会被渲染出来。
三、具名插槽
具名插槽用于接收父组件中明确指定插槽名称的内容。它允许一个组件内有多个插槽,每个插槽可以有不同的内容。
1. 基本语法
在子组件中使用<slot name="插槽名称"></slot>
定义具名插槽,父组件中通过<template v-slot:插槽名称>
或简写为<template #插槽名称>
来指定内容应该插入哪个具名插槽。
2. 代码示例
子组件(NamedSlotChild.vue):
<template>
<div class="child">
<header>
<!-- 具名插槽: header -->
<slot name="header"></slot>
</header>
<main>
<!-- 默认插槽 -->
<slot></slot>
</main>
<footer>
<!-- 具名插槽: footer -->
<slot name="footer"></slot>
</footer>
</div>
</template>
父组件:
<template>
<NamedSlotChild>
<template v-slot:header>
<!-- 这里的内容会被渲染到子组件的header插槽中 -->
<h1>这是标题</h1>
</template>
<p>这是默认插槽的内容。</p>
<template v-slot:footer>
<!-- 这里的内容会被渲染到子组件的footer插槽中 -->
<p>这是页脚</p>
</template>
</NamedSlotChild>
</template>
<script>
import NamedSlotChild from './NamedSlotChild.vue';
export default {
components: {
NamedSlotChild
}
}
</script>
在这个例子中,父组件为子组件的header插槽和footer插槽分别提供了内容,而默认插槽则接收了一个段落标签。
3. v-slot的简写
v-slot的写法较长,Vue提供了一个简写方式,即将v-slot:
简写为#
。
<template #header>
<!-- 这里的内容会被渲染到子组件的header插槽中 -->
<h1>这是标题</h1>
</template>
四、作用域插槽
作用域插槽是一种特殊的插槽,它允许子组件将数据暴露给父组件的插槽内容。这样,父组件可以使用子组件传递的数据来定制插槽的内容。
1. 基本语法
在子组件中,通过<slot :数据名="数据值"></slot>
将数据传递给插槽。在父组件中,通过<template v-slot:插槽名称="slotProps">
接收数据,并使用slotProps来访问传递过来的数据。
2. 代码示例
子组件(ScopedSlotChild.vue):
<template>
<ul>
<li v-for="item in items" :key="item.id">
<slot name="item" :item="item">{{ item.text }}</slot>
</li>
</ul>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, text: '苹果' },
{ id: 2, text: '香蕉' },
{ id: 3, text: '橙子' }
]
}
}
}
</script>
父组件:
<template>
<ScopedSlotChild>
<template v-slot:item="slotProps">
<!-- 使用slotProps访问子组件传递的数据 -->
<strong>{{ slotProps.item.text }}</strong>
</template>
</ScopedSlotChild>
</template>
<script>
import ScopedSlotChild from './ScopedSlotChild.vue';
export default {
components: {
ScopedSlotChild
}
}
</script>
在这个例子中,子组件将items数组中的每个元素通过作用域插槽传递给父组件,父组件使用slotProps访问传递过来的数据,并将其渲染为粗体文本。
3. 动态插槽名
插槽的名称也可以是动态的,根据组件的状态或其他条件来决定使用哪个插槽。在父组件中,通过:slot="动态名称"
来绑定插槽的名称,其中动态名称可以是一个计算属性、方法返回值或数据属性。
五、综合案例:封装表格组件
在实际项目中,封装表格组件是一个常见的需求。通过插槽,我们可以自定义表格的每一列,使其能够适应不同的数据类型和展示方式。
代码准备
根组件(APP.vue):
<template>
<div>
<MyTable :data="list1">
<!-- 使用插槽 -->
<template #default="obj">
<button @click="del(obj.row.id)">删除</button>
</template>
</MyTable>
<MyTable :data="list2">
<template v-slot:default="{ row }">
<button @click="show(row)">查看</button>
</template>
</MyTable>
</div>
</template>
<script>
import MyTable from './components/MyTable.vue';
export default {
data() {
return {
list1: [
{ id: 1, name: '赵天明', age: 25 },
{ id: 2, name: '李翔飞', age: 22 },
{ id: 3, name: '吴国基', age: 24 }
],
list2: [
{ id: 4, name: '王小明', age: 26 },
{ id: 5, name: '张小丽', age: 23 },
{ id: 6, name: '李大力', age: 27 }
]
};
},
methods: {
del(id) {
this.list1 = this.list1.filter(item => item.id !== id);
},
show(row) {
alert(`姓名:${row.name}; 年龄:${row.age}`);
}
},
components: {
MyTable
}
}
</script>
子组件(MyTable.vue)
<template>
<div class="my-table">
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="row in data" :key="row.id">
<td>{{ row.id }}</td>
<td>{{ row.name }}</td>
<td>{{ row.age }}</td>
<td>
<!-- 使用插槽来渲染操作列 -->
<slot :row="row"></slot>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name: 'MyTable',
props: {
data: {
type: Array,
required: true
}
}
}
</script>
<style scoped>
.my-table {
width: 100%;
border-collapse: collapse;
}
.my-table th, .my-table td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
.my-table th {
background-color: #f2f2f2;
}
</style>
综合案例解析
在这个综合案例中,我们封装了一个简单的表格组件MyTable
,它接收一个data
属性,该属性是一个对象数组,每个对象代表表格中的一行数据。MyTable
组件内部使用v-for
指令遍历data
数组,并为每一行数据生成一个表格行(<tr>
)。
在表格的最后一列(操作列),我们使用了插槽(<slot :row="row"></slot>
),这样父组件就可以自定义这一列的内容。通过v-slot:default="{ row }"
语法,父组件可以接收到子组件传递的每一行数据,并据此渲染相应的操作按钮或链接。
父组件中的使用
在父组件中,我们创建了两个数据列表list1
和list2
,并分别将它们传递给两个MyTable
组件实例。对于第一个MyTable
组件实例,我们使用了一个带命名的插槽(虽然这里使用的是默认插槽,但命名插槽的语法类似),并通过@click
事件监听器绑定了删除操作。对于第二个MyTable
组件实例,我们使用了简写的插槽语法,并通过show
方法实现了查看操作。
插槽的作用
在这个案例中,插槽的作用主要体现在以下几个方面:
-
提高组件的复用性:通过插槽,我们可以将表格的操作列留给父组件自定义,这样
MyTable
组件就可以适用于不同的场景,而无需修改组件本身的代码。 -
实现数据的灵活展示:父组件可以根据需要传递不同的数据给子组件,并通过插槽展示这些数据。在这个案例中,父组件通过插槽传递了删除和查看两个操作按钮,而这两个操作的具体实现则是由父组件控制的。
-
保持组件的简洁性:将复杂的展示逻辑放在父组件中处理,可以使子组件保持简洁和专注。在这个案例中,
MyTable
组件只负责渲染表格的基本结构,而具体的操作逻辑则留给父组件实现。
六、总结
插槽是Vue中一个非常强大的功能,它允许我们在子组件中定义插槽位置,并在父组件中填充这些内容。通过插槽,我们可以实现组件的高度自定义和复用性。在本文中,我们详细介绍了默认插槽、具名插槽和作用域插槽的基本用法,并通过一个综合案例展示了如何在实际项目中应用这些插槽类型来封装表格组件。希望这些内容能帮助你更好地理解和使用Vue中的插槽功能。