在Vue
中,我们使用组件来组织页面和组织代码,类似于搭积木,每一个组件都是一个积木,使用一些相同或者不同组件就能搭建出我们想要的页面。slot
(插槽)是组件功能的重要组成部分,插槽必须用于组件才有意义。它为组件提供了对外的接口,允许从组件外部传递内容,并将这部分内容放置到指定的位置。
使用 slot
当一个组件可能被使用至少两次并且两次使用内容(这里指组件视图的组成)不同时,插槽才有存在的必要。注意: 本文的代码都是基于Vue3编写。
基础用法
Link.vue
<template>
<a :href="href" class="link">
<!-- 留个插槽,外界传入内容放置在这里 -->
<slot></slot>
</a>
</template>
<script>
export default {
props: {
href: {
required: true,
type: String,
},
},
};
</script>
<style lang="less" scoped>
.link {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
border: 1px solid #dcdfe6;
color: #606266;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: 0.1s;
font-weight: 500;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
}
</style>
App.vue
<template>
<div class="app">
<Link href="https://baidu.com"> 百度</Link>
<br />
<Link href="https://google.com" style="margin-top: 10px">
<!-- 这里允许放置任意的内容,包括字符串和标签 -->
<span>Icon</span>谷歌</Link
>
</div>
</template>
<script>
import Link from "./Link.vue";
export default {
components: {
Link,
},
};
</script>
视觉效果:
以上实现了两个组件Link.vue
和App.vue
,Link.vue
是一个链接组件,在组件内部已经定义好了样式,然后链接的内容交由外界使用时填充。在App.vue
组件内则使用了Link.vue
组件两次,并且两次传入的内容不同。
具名插槽
上面的Link.vue
只要求填充一份内容,那么当我们需要在组件的好几个位置都填充不同的内容应该怎么办?这时候可以使用具名插槽,就是给组件的每个填充区域都取个名字,这样在使用的时候就可以往对应名字的那个区域填充内容。
Page.vue
<template>
<div class="page">
<header class="page-header">
<slot name="header"></slot>
</header>
<div class="page-center">
<aside class="page-aside">
<slot name="aside"></slot>
</aside>
<div class="page-content">
<slot name="content"></slot>
</div>
</div>
<footer class="page-footer">
<slot name="footer"></slot>
</footer>
</div>
</template>
<script>
export default {
setup() {
return {};
},
};
</script>
<style lang="less">
body {
margin: 0;
}
.page {
border: 1px solid #333;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
&-header {
height: 50px;
border-bottom: 1px solid #333333;
}
&-center {
flex: 1;
display: flex;
}
&-aside {
width: 150px;
border-right: 1px solid #333333;
}
&-content {
flex: 1;
}
&-footer {
border-top: 1px solid #333;
height: 30px;
}
}
</style>
App.vue
<tem