插槽 (Slots)
# 插槽 (Slots)
# 1. 什么是插槽
插槽(Slot)是 Vue 提供的一种技术,允许开发者在封装组件时,预留出可由组件使用者填充的内容区域。可以把插槽看作是组件封装期间,为用户预留的内容占位符。
# 2. 体验插槽的基础用法
在封装组件时,可以通过 <slot>
元素定义插槽,从而为用户预留内容占位符。
子组件
<!-- ChildComponent.vue -->
<template>
<div>
<h2>子组件</h2>
<slot></slot> <!-- 定义插槽 -->
</div>
</template>
<script>
export default {
name: 'ChildComponent'
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
父组件
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<ChildComponent>
<p>这是插入到子组件中的内容</p>
</ChildComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
在这个示例中,父组件 ParentComponent
使用了子组件 ChildComponent
,并向子组件的插槽中传递了一段 <p>
标签内容。渲染后的结果会在子组件的插槽位置显示父组件传递的内容。
# 3. 没有预留插槽的内容会被丢弃
如果在封装组件时没有预留任何 <slot>
插槽,则用户提供的任何自定义内容都会被丢弃。
子组件
<!-- ChildComponent.vue -->
<template>
<div>
<h2>子组件(没有插槽)</h2>
</div>
</template>
<script>
export default {
name: 'ChildComponent'
};
</script>
2
3
4
5
6
7
8
9
10
11
12
父组件
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<NoSlotComponent>
<p>这个内容将会被丢弃,因为子组件没有定义插槽</p>
</NoSlotComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
在这个示例中,父组件向 NoSlotComponent
传递的 <p>
标签内容将会被丢弃,因为子组件 NoSlotComponent
没有定义任何插槽。
# 4. 后备内容 (默认插槽)
封装组件时,可以为预留的 <slot>
插槽提供后备内容(默认内容)。如果组件的使用者没有为插槽提供任何内容,则后备内容会生效。
子组件
<!-- ChildComponent.vue -->
<template>
<div>
<h2>子组件(带默认插槽内容)</h2>
<slot>这是默认内容,如果没有插入内容,则显示这段文字</slot>
</div>
</template>
<script>
export default {
name: 'ChildComponent'
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
父组件
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<ChildComponent>
<!-- 这里没有插入内容,子组件会显示默认内容 -->
</ChildComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
在这个示例中,如果父组件没有向子组件 DefaultSlotComponent
的插槽中插入内容,则子组件会显示插槽中的默认内容 “这是默认内容,如果没有插入内容,则显示这段文字”。
# 5. 具名插槽 (v-slot)
在组件封装过程中,如果需要预留多个插槽,可以为每个 <slot>
插槽指定一个具体的 name
名称。这种带有具体名称的插槽叫做“具名插槽”。具名插槽允许开发者更灵活地分配内容到不同的插槽位置。
提示
v-slot
指令用于在父组件中绑定具名插槽的名称,并且v-slot
指令只能用于 <template>
标签上。
# 5-1 子组件中定义具名插槽
子组件
<!-- ChildComponent.vue -->
<template>
<div>
<h2>子组件</h2>
<slot name="header"></slot> <!-- 定义名为 header 的插槽 -->
<slot></slot> <!-- 定义一个默认插槽 -->
<slot name="footer"></slot> <!-- 定义名为 footer 的插槽 -->
</div>
</template>
<script>
export default {
name: 'ChildComponent'
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 5-2 父组件中向具名插槽提供内容
在父组件中使用 <template>
标签并结合 v-slot
指令向具名插槽传递内容。需要注意的是,v-slot
指令只能用于 <template>
标签上。
父组件
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<ChildComponent>
<template v-slot:header>
<p>这是传递给 header 插槽的内容</p>
</template>
<p>这是传递给默认插槽的内容</p>
<template v-slot:footer>
<p>这是传递给 footer 插槽的内容</p>
</template>
</ChildComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
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
在这个示例中,父组件 ParentComponent
使用了子组件 ChildComponent
,并向具名插槽 header
和 footer
传递了不同的内容,同时也向默认插槽传递了内容。
# 6. 具名插槽的简写形式
为了简化代码,Vue 提供了 v-slot 指令的简写形式。可以使用 #
代替 v-slot:
,例如 v-slot:header
可以简写为 #header
。
父组件
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<ChildComponent>
<template #header>
<p>这是传递给 header 插槽的内容</p>
</template>
<p>这是传递给默认插槽的内容</p>
<template #footer>
<p>这是传递给 footer 插槽的内容</p>
</template>
</ChildComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
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
在这个示例中,使用了 #header
和 #footer
来简写 v-slot:header
和 v-slot:footer
,使得代码更简洁。
通过使用具名插槽,开发者可以在一个组件中定义多个内容占位符,并且可以灵活地控制不同内容的显示位置。这使得组件的复用性和灵活性大大提高。
# 8. 作用域插槽
在 Vue 组件开发中,可以通过定义作用域插槽(Scoped Slots)来实现组件之间的数据共享。作用域插槽允许子组件将数据传递给父组件,从而使父组件能够动态地渲染内容。
# 8-1 子组件中定义作用域插槽
在子组件中,可以通过 <slot>
元素结合 v-bind
指令来定义作用域插槽,并将数据绑定到插槽上。
子组件
<!-- ChildComponent.vue -->
<template>
<div>
<h2>子组件</h2>
<!-- 定义一个作用域插槽,并向其绑定 props 数据 -->
<slot :user="user"></slot>
</div>
</template>
<script>
export default {
name: 'ChildComponent',
data() {
return {
user: { name: 'John Doe', age: 25 } // 定义一些数据
};
}
};
</script>
<style scoped>
/* 子组件的样式 */
h2 {
color: blue;
}
</style>
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
在这个示例中,子组件 ChildComponent
定义了一个作用域插槽 <slot :user="user"></slot>
,并向其绑定了 user
数据。通过这种方式,子组件可以将 user
数据传递给使用该组件的父组件。
# 8-2 父组件中使用作用域插槽
在父组件中,可以通过 <template>
元素结合 v-slot
指令接收作用域插槽提供的数据,并在插槽中使用这些数据。
父组件
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<ChildComponent>
<!-- 使用 v-slot 指令接收作用域插槽提供的数据 -->
<!-- v-slot:default 是固定写法,表示接收子组件默认插槽的数据 -->
<template v-slot:default="slotProps">
<p>用户名称:{{ slotProps.user.name }}</p>
<p>用户年龄:{{ slotProps.user.age }}</p>
</template>
</ChildComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
<style scoped>
/* 父组件的样式 */
h1 {
color: red;
}
</style>
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
30
31
在这个示例中,父组件 ParentComponent
使用 <template v-slot:default="slotProps">
接收子组件传递的 user
数据。这里的 v-slot:default
是 Vue 的固定写法,用于接收子组件默认插槽的数据。slotProps
是一个对象,包含了子组件传递的数据。
提示
如果要接收具名插槽的数据,可以使用 v-slot:name
的形式,其中 name
是插槽的名称,还可以简写成 #name
的形式。
# 8-3 使用解构赋值简化数据的接收过程
为了简化代码,可以使用解构赋值直接从 slotProps
对象中提取所需的数据。这种方式可以使代码更加简洁和易读。
父组件
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<ChildComponent>
<!-- 使用解构赋值简化数据的接收过程 -->
<!-- v-slot:default 是固定写法,解构赋值可以直接提取 user 数据 -->
<template v-slot:default="{ user }">
<p>用户名称:{{ user.name }}</p>
<p>用户年龄:{{ user.age }}</p>
</template>
</ChildComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
<style scoped>
/* 父组件的样式 */
h1 {
color: red;
}
</style>
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
30
31
在这个示例中,父组件 ParentComponent
使用解构赋值直接从 slotProps
对象中提取 user
数据。通过这种方式,父组件可以更加方便地访问子组件传递的数据。
# 8-4 具名作用域插槽
如果子组件定义了具名插槽,父组件可以使用 v-slot:name
的形式接收这些插槽的数据。
子组件
<!-- ChildComponent.vue -->
<template>
<div>
<h2>子组件</h2>
<!-- 定义具名插槽 -->
<slot name="header" :user="user"></slot>
<slot name="footer"></slot>
</div>
</template>
<script>
export default {
name: 'ChildComponent',
data() {
return {
user: { name: 'John Doe', age: 25 } // 定义一些数据
};
}
};
</script>
<style scoped>
/* 子组件的样式 */
h2 {
color: blue;
}
</style>
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
父组件
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<ChildComponent>
<!-- 使用 v-slot:header 指令接收具名插槽的数据 -->
<template v-slot:header="{ user }">
<p>用户名称:{{ user.name }}</p>
</template>
<template v-slot:footer>
<p>这是底部内容</p>
</template>
</ChildComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
<style scoped>
/* 父组件的样式 */
h1 {
color: red;
}
</style>
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
30
31
32
33
在这个示例中,父组件 ParentComponent
使用 <template v-slot:header="{ user }">
接收子组件具名插槽 header
传递的数据,并使用 <template v-slot:footer>
提供子组件具名插槽 footer
的内容。
# 8-5 具名作用域插槽的简写形式
跟 v-on
和 v-bind
一样,v-slot
也有缩写形式,即把参数之前的所有内容(v-slot:
)替换为字符 #
。例如 v-slot:header
可以被简写为 #header
。
父组件(简写形式)
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<ChildComponent>
<!-- 使用 v-slot:header 的简写形式接收具名插槽的数据 -->
<template #header="{ user }">
<p>用户名称:{{ user.name }}</p>
</template>
<template #footer>
<p>这是底部内容</p>
</template>
</ChildComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
<style scoped>
/* 父组件的样式 */
h1 {
color: red;
}
</style>
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
30
31
32
33
在这个示例中,父组件 ParentComponent
使用 #header="{ user }"
接收子组件具名插槽 header
传递的数据,使用 #footer
提供子组件具名插槽 footer
的内容。
总结
- 定义作用域插槽:在子组件中定义
<slot>
插槽时,可以使用v-bind
绑定数据。这些数据将作为props
传递给父组件中的插槽。 - 使用作用域插槽:在父组件中使用
<template>
元素结合v-slot
指令接收子组件传递的数据。v-slot:default
是 Vue 的固定写法,用于接收子组件默认插槽的数据。如果要接收具名插槽的数据,可以使用v-slot:name
的形式,其中name
是插槽的名称。 - 解构插槽 Prop:为了简化代码,可以使用解构赋值直接从数据对象中提取所需的数据。