发布于 

slot的使用

默认插槽

假设子组件<son>组件的模版如下:

1
2
3
4
5
6
7
8
9
10
11
<div class="container">
<header>
<h1>头部</h1>
</header>
<main>
<slot></slot>
</main>
<footer>
<h1>w尾部</h1>
</footer>
</div>

利用slot特性,我们可以在一个父组件<father>中向<son>提供内容,如下:

1
2
3
4
5
6
7
8
9
<son>
<template v-slot:default>
<h1>
n内容区
</h1>
</template>
</son>
<!--这里也可以省略template和v-slot(vue会默认把h1放到默认插槽里面)-->
<!--只要出现多个插槽,请始终为所有的插槽使用完整的基于 <template> 的语法:-->

具名插槽

假设子组件<son>组件的模版如下:

1
2
3
4
5
6
7
8
9
10
11
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>

在父组件<father>可使用v-slot分别向插槽放置对应的内容

1
2
3
4
5
6
7
8
9
10
11
12
<son>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>

<p>A paragraph for the main content.</p>
<p>And another one.</p>

<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</son>

作用域插槽

使用作用域插槽可让插槽内容能够访问子组件中才有的数据

能够用于父子通信

假设我想从父组件<father>访问子组件<son>的username属性,可以这样做

在子组件<son>内部的slot元素上动态绑定一个username属性:

1
2
3
4
5
6
7
<div class="container">
<span>
<slot :user="user"> <!-- user为自己在data中定义的数据-->
{{ user.username }}
</slot>
</span>
</div>

在父组件<father>中,可以通过v-slot来访问user数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
<son>
<template v-slot:default="slotProps">
{{ slotProps.user.username }}
</template>
</son>

<!-- 按照我的理解,其中的slotProps就相当于是一个包含user对象的参数对象-->
<!-- 这样解构赋值的方式来传入具体的插槽prop,如下: -->
<son>
<template v-slot:default="{ user }">
{{ user.username }}
</template>
</son>
如果插槽传递的数据为引用类型(如:对象),父组件还可以对它进行修改,父元素也可以往插槽内的元素绑定事件(在父元素中触发),代码如下:

子组件<son>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div>
<slot :user="userInfo"></slot>
</div>
</template>

<script>
export default {
data(){
return {
userInfo:{username:'zhangs',userage:18}
}
}
}
</script>

父组件<father>:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<son>
<template v-slot:default="{ user }">

<button @click="getDataFromSon(user)"></button>

</template>
</son>
</template>

<script>
export default {
methods:{
getDataFromSon(obj){
//可以修改子组件的引用类型数据,但只限于该子组件,对其他组件没有影响
this.$set(obj,'username','lisi') //使用this.$set修改为响应式
}
}
}
</script>

简写

在vue中,v-slot和v-on、v-bind类似,v-slot也有简写,用#代替v-slot。例如:v-slot:header简写成 # header

值得注意:当你使用template和v-slot声明某个插槽后,就不能再重复声明了,以下情况就会报错

1
2
3
4
5
6
7
<template v-slot:default>
<span>{{date}}</span>
</template>

<template v-slot:default>
<span>{{date}}</span>
</template>

怎样使用slot

假设我要制作的一个回复框组件,作者的回复框和其他人的回复框有些内容或功能不一样(如下图:第一个个为作者回复框,第二个为其他人的回复框),像这种情况就可以使用插槽

tupian1

子组件UseSlot代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div class="container">
<div class="topic-post">
<div class="avatar-box">
<img src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png" alt="">
</div>
<div class="topic-body">
<div class="info">
<span>{{userInfo.username}}</span>

<slot></slot> <!-- 默认插槽显示所有人共有的内容或功能 -->

</div>
<div class="article">
<p>请教一下大家,有谁知道像vue官方文档,或者elementUI在线文档是怎么做出来的吗</p>
</div>

<slot name="author" ></slot> <!-- 具名插槽只显示作者的内容或功能 -->

</div>
</div>
</div>
</template>

父组件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
<template>
<div class="app">
<!-- 制作回复框组件,作者的回复框和别人的回复框不一样(使用slot) -->
<UseSlot>
<template v-slot:default>
<span>{{date}}</span>
</template>

<template v-slot:author>
<div class="post-menu">
<button >回复</button>
<div class="actions">
<button>点赞</button>
<button>分享</button>
</div>
</div>
</template>
</UseSlot>

<UseSlot >
<template v-slot:default>
<span></span>
</template>
</UseSlot>
</div>
</template>