Skip to content

Vue 组件插槽

Vue 组件插槽

简介

子组件能够通过 props 接收父组件传递的任意类型的 JavaScript 值在子组件中使用。

但组件要如何接收模板内容呢?

在某些场景中,可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。

类似 HTML 中通过元素的 html() 方法,向元素中添加另外一个元素或一个元素的组合(表格行及行中的列值)。

此时通过 props 就无法完成该需求,需要使用组件中的另一个概念插槽实现。

插槽内容与出口

Vue 提供一个 <slot></slot> 元素做为插槽的出口,使用 <slot> 作为一个占位符,将父组件传递进来的内容渲染在这里。

插槽内容可以是任意合法的模板内容,不局限于文本,可以传入多个元素,甚至是组件。

并且,插槽内可以有默认内容,如果在使用组件时没有为插槽提供内容,则渲染默认内容。

通过使用插槽,组件更加灵活和具有可复用性。现在组件可以用在不同的地方渲染各异的内容,但同时还保证都具有相同的样式。

SlotOC.vue

<template>
    <p>被用在插槽中的组件</p>
</template>

SlotSC.vue

<template>
    <hr>
    <h2>这是一个具有插槽的组件,下面是插槽中的内容</h2>
    <slot><h4>这是插槽默认内容</h4></slot>
    <hr>
</template>

SlotFC.vue

<script setup>
    import SlotOC from './SlotOC.vue';
    import SlotSC from './SlotSC.vue';
</script>

<template>
    <h1>这是父组件内容</h1>

    <SlotSC> 这是向子组件插槽中添加的一段文本 </SlotSC>
    <SlotSC>
        <div>
            <ul>
                <li>这是向子组件插槽中添加的一个复合HTML元素1</li>
                <li>这是向子组件插槽中添加的一个复合HTML元素2</li>
                <li>这是向子组件插槽中添加的一个复合HTML元素3</li>
            </ul>
        </div>
    </SlotSC>

    <SlotSC>
        <SlotOC></SlotOC>
    </SlotSC>
</template>

App.vue

<script setup>
    import SlotFC from './components/MyComponents/SlotFC.vue';
</script>

<template>
    <SlotFC></SlotFC>
</template>

具名插槽

有些情况下,一个组件中需要包含多个插槽,此时在使用该组件向插槽中传递数据时,如何区别哪个数据放在哪个插槽中呢?

对于这种场景,<slot> 元素可以设置一个特殊的属性 name,用来给各个插槽分配唯一的 ID,以确定每一处要渲染的内容。

没有提供 name 的插槽会被隐式的命名为 default

    <!-- 具名插槽 -->
    <slot name="sloatname"></slot>

    <!-- 未具名插槽,默认名为 default -->
    <slot></slot>

v-slot

要为具名插槽传入内容,我们需要使用一个含 v-slot 指令的 <template> 元素,并将目标插槽的名字传给该指令。

当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非 <template> 节点都被隐式地视为默认插槽的内容。

v-slot 指令也可以简写为 #

    <!-- 标准形式 -->
    <template v-slot:sloatname></template> 
    <!-- 简写形式 -->
    <template #sloatname></template> 

SlotnameSC.vue

<template>
    <hr>
    <h2>这是一个具有插槽的组件,下面是插槽中的内容</h2>
    <div class="container">
        <header>
            <slot name="header"></slot>
        </header>
        <main>
            <slot></slot>
        </main>
        <footer>
            <slot name="footer"></slot>
        </footer>
    </div>
    <hr>
</template>

SlotnameFC.vue

<script setup>
    import SlotnameSC from './SlotnameSC.vue';
</script>

<template>
    <h1>这是父组件内容</h1>

    <SlotnameSC>
        <template v-slot:header>
            <h1>这是页面标题</h1>
        </template>n

        <template #default>
            <p>这是内容显示区域</p>
            <p>用来显示文本和图片</p>
        </template>

        <!-- <p>这是内容显示区域</p>
        <p>用来显示文本和图片</p> -->

        <template #footer>
            <p>这里显示页脚信息</p>
        </template>
    </SlotnameSC>
</template>

App.vue

<script setup>
    import SlotnameFC from './components/MyComponents/SlotnameFC.vue';
</script>

<template>
    <SlotnameFC></SlotnameFC>
</template>

总结

  • 组件中除能显示 props接收的数据外,还可以通过 <slot></slot> 设置一个插槽占位符,用来接收需要渲染的内容。
  • 插槽中除文本外,还可以渲染元素,甚至是一个组件
  • 一个组件中可以有多个插槽,通过 name 属性为插槽具名。
  • 为具名插槽传递数据时,需要配合使用 template 元素。并使用属性 v-slot:slotname#slotname 方式指定插槽。