Vue中的插槽是一个非常强大的功能,在复用组件模块的时候,针对相似的结构,拥有不通的内容时,使用插槽就非常方便,一定程度上可以减少在模板中使用大量的逻辑判断,控制显示不通的内容
同时,也可以让代码组织结构更加清晰,虽然使用上是简单了,但是插槽有些不是很好理解,不是很直观
它是让父组件可以向子组件指定位置处插入一html结构,自由灵活,也是组件间的一种通信方式
形式上有,默认插槽
,具名插槽
还有作用域插槽
大家在使用element-ui
表格的时候,虽然都知道怎么用,表头,以及内容模板的渲染,就使用了插槽,但是往往是很迷糊的
因为被抽象了的
今天就一起来学习下,学完之后,在看element-ui
表格的时候,希望能给你带来一些启发,下次再次使用时,理解更上一层楼
默认插槽
官方文档里介绍到:Vue
实现了一套内容分发的 API
,这套 API
的设计灵感源自 Web Components
规范草案,将 <slot>
元素作为承载分发内容的出口
这句话不是很好理解,换句话说,也就是,<slot>
可以充当元素标签的占位符,可以代替在父组件引用的组件内的html
标签内容
以如下示例所示
在App.vue
组件中引入SlotBase.vue
组件
<template>
<div id="app">
<SlotBase
:lists="lists">
<p>默认内容</p>
</SlotBase>
</div>
</template>
<script>
import SlotBase from "./components/SlotBase.vue"
export default {
name: 'App',
components: {
SlotBase
},
data() {
return {
lists: [
{
id: "001",
title: "直播卖酒"
},
{
id: "002",
title: "直播打赏"
},
{
id: "003",
title: "直播炫富"
}
]
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
而在编写SlotBase.vue
组件中,引入slot
标签,如下所示
<template>
<div class="wrap">
<div class="list" v-for="list in lists" :key="list.id">
{{list.title}}
<!-- 此处引入slot标签 -->
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: "SlotBase",
props: {
lists: {
type: Array
}
},
mounted() {
console.log(this.lists);
}
}
</script>
<style lang="scss" scoped>
.wrap {
display: flex;
justify-content: center;
}
.list {
width: 400px;
height: 200px;
border:1px solid red;
margin-right: 10px;
}
</style>
在子组件内的<slot></slot>
标签就是插槽,代替了在父组件内的<p>默认内容</p>
如果你在父组件的自定义标签内,插入了html
模板,在子组件没有使用slot,
那么父组件内插入的标签内容是不会被插入进去的
现在知道插槽是什么了吧,可以在组件标签内定义需要的内容,通过插槽加入到组件内部中
组件内部的<slot></slot>
元素就好像一个传送门,也就是所谓的槽,它提供了内容的入口,也决定了内容的位置。 组件标签中定义的内容,通过这个“传送门”就可以加入到组件内部中
插槽中的“插件”就是组件标签中的内容。
插槽中的“槽”就是在组件中的<slot></slot>
元素,当没有<slot></slot>
元素的时候,就不渲染组件标签中的内容
当是默认插槽时,我们可以使用template
标签给包裹起来的,并且在上面添加v-slot:default
属性,这代表的是默认插槽
<template v-slot:default>
<p>默认内容</p>
</template>
具名插槽
如果要将不通的内容放在不通的位置,那么默认插槽就无法办到了
顾名思义,具名插槽,就是给插槽定义一个名字,让每个不通的模板对应着不通的名字
我们给在父组件内的插入的模板属性上添加v-slot:插槽名字,
而在子组件内通过添加name
属性<slot name="插槽名字"></slot>
需要注意的是,name的值需要与v-slot的值要一一对应,如果对不上的话,那么就会达不到我们预期的效果
如下示例代码所示:在App
父组件中
<template>
<div id="app">
<SlotBase
:lists="lists">
<template v-slot:default>
<p>默认内容</p>
</template>
<template v-slot:content>
<p>我是直播卖酒-content</p>
</template>
<!-- <template v-slot:content2>
<p>我是直播打赏-content</p>
</template> -->
<!-- 可以简写成如下所示 -->
<template #content2>
<p>我是直播打赏-content</p>
</template>
</SlotBase>
</div>
</template>
<script>
import SlotBase from "./components/SlotBase.vue"
export default {
name: 'App',
components: {
SlotBase
},
data() {
return {
lists: [
{
id: "001",
title: "直播卖酒",
},
{
id: "002",
title: "直播打赏"
},
{
id: "003",
title: "直播炫富"
}
]
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
而在子组件,slotBase.vue
中
<template>
<div class="wrap">
<div class="list" v-for="list in lists" :key="list.id">
{{list.title}}
<!-- 此处引入slot标签 -->
<slot></slot>
<slot name="content" v-if="list.title =='直播卖酒'"></slot>
<slot name="content2" v-if="list.title =='直播打赏'"></slot>
</div>
</div>
</template>
<script>
export default {
name: "SlotBase",
props: {
lists: {
type: Array
}
},
mounted() {
console.log(this.lists);
}
}
</script>
<style lang="scss" scoped>
.wrap {
display: flex;
justify-content: center;
}
.list {
width: 400px;
height: 200px;
border:1px solid red;
margin-right: 10px;
}
</style>
上面我用了一个v-if
条件渲染表达式,我们可以可以根据一些条件控制元素的显示和隐藏
上面的具名插槽,在父组件中v-slot:content
可以缩写为#content,
当我们看到这种简写的时候,知道它也是给插槽起一个具体的名字即可
它跟 v-on
和 v-bind
一样,v-slot
也有缩写,即把参数之前的所有内容 (v-slot
🙂 替换为字符 #
。例如 v-slot:header
可以被重写为 #header
如果你看不懂,那就是对简写插槽的名称有些陌生了
从上面的示例中,我们可以做出一些总结
1. 具名插槽可以根据名称渲染对应的html
标签模板内容
2. 没有定义名称的内容会被默认插槽统一渲染
3. 默认插槽其实也是一个具名插槽,名称为default
4. 父组件内插槽内容可以是模板html
标签元素,也可以是组件
注意
这个v-slot
只能用在template
标签上
旧版本写法
在父组件上使用v-slot
:插槽名称,这个是vue2.6.0
以后的写法,在vue2.6.0
之前,可以在模板上使用slot="插槽的名称
“