Vue 插槽(slot)使用
Jioho 7/19/2020 Vue
# 介绍
还是老规矩放上官方文档:官方文档 slot (opens new window)
# 内容插槽
这是最基础的插槽
定义两个组件 parent.vue
、children.vue
然后在 parent.vue 组件中引用 children.vue 组件
第 4 行中。就是把值插入插槽中,如果对应组件并没有插槽,则不会渲染中间的内容
<!-- home.vue -->
<template>
<children>
Hello Word
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</children>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
第 4 行中,就是定义了一个插槽
<!-- children.vue -->
<template>
<a href="#">
<slot>这是默认值</slot>
</a>
</template>
1
2
3
4
5
6
2
3
4
5
6
插槽中可以使用的内容
- 插入普通文本
- 插入 HTML
- 插入新的组件
- 使用 {{}} 插入动态数据
插槽默认值
上面的例子中,子组件的 <slot>
中有一段文本这段文本就是默认值,他和插槽一样,可以是任意的内容
如果在引入该组件没有为插槽赋值时,默认值就会被渲染出来
基本上所有的内容都可以插入到插槽中,并没有限制。当然,父组件的插槽中的数据依旧是来自父组件的,并不是来自子组件的
# 具名插槽
上面的是默认插槽,有可能一个复杂的组件中需要有多个插槽的位置,就可以使用具名插槽
<!-- children -->
<template>
<div>
<header>
<!-- 我们希望把页头放这里 -->
<slot name="header"></slot>
</header>
<main>
<!-- 我们希望把主要内容放这里 -->
<slot></slot>
</main>
<footer>
<!-- 我们希望把页脚放这里 -->
<slot name="footer"></slot>
</footer>
</div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 使用
name
属性定义插槽的名称。如果没有 name,默认就是default
- 插槽是可以重复定义的,在子组件中,同名的插槽也会重复渲染
具名插槽的使用
<template>
<children>
<template v-slot:footer>
<p>Here some contact info</p>
</template>
<template #header> 这是头部信息 </template>
<p>Here some contact info</p>
</children>
</template>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- 使用插槽的时候,默认插槽可以不指定
v-slot
- 我们也可以使用新语法:
#slot name
来使用插槽 - 使用
v-slot
来使用插槽 - 插槽的声明顺序并不会影响渲染顺序,渲染顺序又组件的插槽位置决定
# 作用域插槽
所有的插槽渲染都是有作用域的,插槽在哪个页面上渲染,作用域就在当前的页面(无法访问子组件的值)
那如果我们还是想展示子组件里面的值怎么办?
注意是父组件展示子组件的值
我们把需要传递的内容绑到 <slot>
上,然后在父组件中用 v-slot 设置一个值来定义我们提供插槽的名字:
子组件:
<!-- children -->
<div>
<slot :userInfo="user">{{user.name}}</slot>
</div>
<script>
export default {
//定义内容
data() {
return {
user: {
name: 'Jioho',
age: 22
}
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在父组件中使用:
slotProps
名称是自定义的,可以指定默认插槽的数据名称
<!-- home.vue -->
<div>
<children v-slot:default="slotProps">
我是:{{ slotProps.user.name }}
</children>
</div>
1
2
3
4
5
6
2
3
4
5
6
注意
默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:
<template>
<children v-slot="slotProps">
{{ slotProps.user.firstName }}
<template v-slot:other="otherSlotProps">
<!-- slotProps 将不会显示在这里 -->
</template>
</children>
</template>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
多插槽和作用域
- 子组件
<template>
<div>
<span>
<slot v-bind:userData="user" name="header">
{{ user.msg }}
</slot>
<slot v-bind:hobbyData="hobby" name="footer">
{{ hobby.fruit }}
</slot>
</span>
</div>
</template>
<script>
export default {
data() {
return {
user: {
firstName: 'gerace',
lastName: 'haLi'
},
hobby: {
fruit: 'apple',
color: 'blue'
}
}
}
}
</script>
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
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
- 父组件
<template>
<myslot>
<template v-slot:header="slotProps">
{{ slotProps.userData.firstName }}
</template>
<template v-slot:footer="slotProps">
{{ slotProps.hobbyData.fruit }}
</template>
</myslot>
</template>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
结合上面所说的,使用 #
和使用 es6 的解构赋值。父组件可以写成如下写法:
<template>
<myslot>
<template #header="{userData}">
{{ userData.firstName }}
</template>
<template #footer="{hobbyData}">
{{ hobbyData.fruit }}
</template>
</myslot>
</template>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10