说在前面
重点理解掌握作用域插槽,默认插槽和具名插槽简单略过。
默认插槽
- 子组件
<a
v-bind:href="url"
class="nav-link"
>
<slot>后备内容,当slot为空当时候默认使用这里的内容</slot>
</a>
- 父组件
<navigation-link url="/profile">
Your Profile
</navigation-link>
具名插槽
- 子组件
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
一个不带 name
的 <slot>
出口会带有隐含的名字“default”。
任何没有被包裹在带有 v-slot
的 <template>
中的内容都会被视为默认插槽的内容。
- 父组件
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<template v-slot:default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
渲染结果
<div class="container">
<header>
<h1>Here might be a page title</h1>
</header>
<main>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</main>
<footer>
<p>Here's some contact info</p>
</footer>
</div>
作用域插槽 (重难点)
老实说,这个一般主要是用在UI框架上,还有你的子组件千变万化,我写了两年业务代码,没一次用上,但是看到别人的UI框架用到了,你也要知道咋回事。
- 子组件
<template>
<ul>
<li v-for="user in users">
<slot :user="user">
{{ user.id }}
</slot>
<slot name="first" :user="user">
{{ user.firstName }}
</slot>
<slot name="last" :user="user">
{{ user.lastName }}
</slot>
</li>
</ul>
</template>
<script>
export default {
name: "UserList",
props: ['users']
}
</script>
- 父组件
<template>
<div class="hello">
<user-list :users="users">
</user-list>
</div>
</template>
<script>
import UserList from "@/components/UserList";
export default {
name: 'HelloWorld',
components: { UserList },
data() {
return {
users: [
{ id: 1, firstName: 'a1', lastName: 'a2' },
{ id: 2, firstName: 'b1', lastName: 'b2' },
{ id: 3, firstName: 'c1', lastName: 'c2' },
]
}
},
}
</script>
<style scoped>
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>
我们先不在user-list
里写任何内容,那么子组件会按照slot的后备内容进行渲染,渲染如下
可以清楚看到子组件就按id ,firstName,lastName来排开了
下面我来对user-list
里自定义渲染内容
// 省略不变的代码
<user-list :users="users">
<template v-slot="slotProps">
<label class="id-label">{{ slotProps.user.id }}</label>
</template>
</user-list>
// 省略不变的代码
<style scoped>
.id-label{
color: pink;
}
</style>
看结果
可以看到id变颜色了,这是因为我们对数据的自定义渲染生效了。
看上面的代码,我用了v-slot="slotProps"
这是对默认插槽起作用的,省略了default,同时来了个等号,取出了此时定义在子组件中对数据。
slotProps.user.id
为什么是 .user
? 因为子组件中这三行代码
<slot :user="user">
{{ user.id }}
</slot>
在默认插槽中,有一个:user="user"
就是这个冒号后面的user
决定的slotProps.user
,此时就已经拿到了子组件中的这个user数据了,你可以尽情的对这个数据进行任何的渲染。
最后来一个完整的例子。
父组件
<template>
<div class="hello">
<user-list :users="users">
<template v-slot="slotProps">
<label class="id-label">{{ slotProps.user.id }}</label>
</template>
<template v-slot:first="slotProps">
<div class="first-label">{{ slotProps.user.firstName }}</div>
</template>
<template v-slot:last="slotProps">
<button>{{ slotProps.user.lastName }}</button>
</template>
</user-list>
</div>
</template>
<script>
import UserList from "@/components/UserList";
export default {
name: 'HelloWorld',
components: { UserList },
data() {
return {
users: [
{ id: 1, firstName: 'a1', lastName: 'a2' },
{ id: 2, firstName: 'b1', lastName: 'b2' },
{ id: 3, firstName: 'c1', lastName: 'c2' },
]
}
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
.id-label {
color: pink;
}
.first-label {
height: 20px;
width: 20px;
background: cornflowerblue;
display: inline-block;
margin: 0 20px;
}
</style>
最后把源码放上:vue-slot-demo