20、Vue 3 (2024 版)基础笔记 - 插槽 Slots

作者: 温新

图书: 【Vue 3 setup 使用实记】

阅读: 347

时间: 2024-11-20 19:57:54

我们已经了解到组件能够接收任意类型的 JavaScript 值作为 props,但组件要如何接收模板内容呢?在某些场景中,我们可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。

<slot> 元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。

插槽的基础使用

1、创建插槽组件

src/components/slots/BaseSlot.vue

<template>
    <div>
        <h3>插槽的基础使用</h3>
        <!-- 显示插槽内容 -->
        <slot></slot>
    </div>
</template>

<script setup lang="ts"></script>
2、父组件引入子组件

src/App.vue

<template>
    <BaseSlot>
        <div>
            <p>父组件传递的数据</p>
            <main>
                <p>插槽内容</p>
            </main>
        </div>
    </BaseSlot>
</template>

<script setup lang="ts">
    import BaseSlot from "./components/slots/BaseSlot.vue"
</script>

插槽渲染作用域

如果有动态数据,那么这个动态数据是在子组件中进行渲染,还是在父组件中进行渲染?官方是这样说的:"插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的。"

答案:在父组件中进行渲染。

1、父组件

src/App.vue

<template>
    <BaseSlot>
        <div>
            <p>父组件传递的数据</p>
            <main>
                <ul>
                    <li v-for="article in articles" :key="article.id">{{ article.title }}</li>
                </ul>
            </main>
        </div>
    </BaseSlot>
</template>

<script setup lang="ts">
    import {ref} from "vue"
    import BaseSlot from "./components/slots/BaseSlot.vue"

    const articles = ref([
        {id:1, title:"我的世界真奇妙"},
        {id:2, title:"王美丽呀"}
    ])
</script>
2、子组件

src/components/slots/BaseSlot.vue

<template>
    <div>
        <h3>插槽的基础使用</h3>
        <!-- 显示插槽内容 -->
        <slot></slot>
    </div>
</template>

<script setup lang="ts"></script>

具名插槽

具名插槽,就是有名字的插槽。

v-slot 有对应的简写 #,因此 <template v-slot:header> 可以简写为 <template #header>。其意思就是“将这部分模板片段传入子组件的 header 插槽中”。

1、父组件中定义具名插槽

src/App.vue

<template>
    <BaseSlot>
        <!-- 使用 # 号简写 -->
        <template #header>
            <nav>
                导航栏部分
            </nav>
        </template>
        <!-- 使用 v-slot -->
        <template v-slot:main>
            <div>
                <main>
                    <ul>
                        <li v-for="article in articles" :key="article.id">{{ article.title }}</li>
                    </ul>
                </main>
            </div>
        </template>
    </BaseSlot>
</template>

<script setup lang="ts">
    import {ref} from "vue"
    import BaseSlot from "./components/slots/BaseSlot.vue"

    const articles = ref([
        {id:1, title:"我的世界真奇妙"},
        {id:2, title:"王美丽呀"}
    ])
</script>
2、子组件使用具名插槽

src/components/slots/BaseSlot.vue

<template>
    <div>
        <slot name="header"></slot>
        <slot name="main"></slot>
    </div>
</template>

<script setup lang="ts"></script>

作用域插槽,子组件传递数据给父组件

通过上面的案例,可以发现数据传递的走向是 子组件使用父组件的数据,如果父组件要使用子组件的数据,该怎么操作?子组件中传递数据。

1、 子组件中使用自定义数据传递数据

src/components/slots/BaseSlot.vue

<template>
    <div>
        <!-- 2、定义一个属性 username,绑定数据是 name -->
        <slot :username="name"></slot>
    </div>
</template>

<script setup lang="ts">
    // 1、子组件定义数据
    const name:string = "王美丽的小世界"
</script>
2、父组件中使用

src/App.vue

<template>
    <!-- 3、父组件插槽中使用  v-slot 接收数据 -->
    <BaseSlot v-slot="slotProps">
        <main>
            <!-- 4、使用数据 -->
            <h3>{{ slotProps.username }}</h3>
            <ul>
                <li v-for="article in articles" :key="article.id">{{ article.title }}</li>
            </ul>
        </main>
    </BaseSlot>
</template>

<script setup lang="ts">
    import {ref} from "vue"
    import BaseSlot from "./components/slots/BaseSlot.vue"

    const articles = ref([
        {id:1, title:"我的世界真奇妙"},
        {id:2, title:"王美丽呀"}
    ])
</script>

具名插槽作用

如果是具名插槽,又该如何使用数据?

1、父组件

src/App.vue

<template>
    <BaseSlot>
        <template #header="slotProps">
            <header>
                头部信息
                <p>{{  slotProps.webinfo }}</p>
            </header>
        </template>

        <template #main="slotProps">
            <main>
                <ul>
                    <li v-for="article in articles" :key="article.id">{{ article.title }}</li>
                </ul>
            </main>
            <p>{{  slotProps.username }}</p>
        </template>
    </BaseSlot>
</template>

<script setup lang="ts">
    import {ref} from "vue"
    import BaseSlot from "./components/slots/BaseSlot.vue"

    const articles = ref([
        {id:1, title:"我的世界真奇妙"},
        {id:2, title:"王美丽呀"}
    ])
</script>
2、子组件

src/components/slots/BaseSlot.vue

<template>
    <slot name="header" :webinfo="info"></slot>
    <slot name="main" :username="name"></slot>
</template>

<script setup lang="ts">
    const info:string = '导航信息'
    const name:string = '王美丽'
</script>
请登录后再评论