插槽与具名插槽以及嵌套插槽的使用

5,508 阅读2分钟

本篇文章内容将会讲解到,插槽与具名插槽以及嵌套插槽的使用方法和场景

插槽 < slot />

插槽简单的来说就是将写在父组件里的内容插入到子组件里

需求:在子组件中显示 '这就是插槽' 几个字

使用方法

1.首先在父组件中引用Dialog子组件,并在中间写入内容

//这是父组件里的代码,引入子组件Dialog
<Dialog >
        <h2>这就是插槽</h2>
</Dialog>

2.告诉子组件在那个地方插入,使用

//这是子组件Dialog的内容
<template>
	<p>下面就是插槽插入的位置</p>
     //slot就是插入的地方
   <slot />
</template>

这样的插槽很简单,但是只能插入一个地方,我要是想在不同的地方插入不同的内容,这该怎么办呢?这就该使用具名插槽

具名插槽

具名插槽就是带有名字的插槽,一个名字一个坑

需求:将标题插入到header里,将内容插入到main里

使用方法

1.在父组件将不同的内容使用template包裹,并使用v-slot起一个名字

<Dialog >
    <template v-slot:title>
        <h2>具名插槽</h2>
    </template>
    <template v-slot:content>
        <p>第一行</p>
        <p>第八行</p>
    </template>
</Dialog>

v-slot可以使用#代替,效果是一样的

<Dialog >
    <template #title>
        <h2>具名插槽</h2>
    </template>
    <template #content>
        <p>第一行</p>
        <p>第八行</p>
    </template>
</Dialog>

2.在子组件将插槽使用名字匹配

<template>
    <div class="gulu-dialog">
        <header>
            <slot name="title" />
        </header>
        <main>
            <slot name="content" />
        </main>
        <footer>
            <Button @click="ok" level="main">OK</Button>
            <Button @click="cancel">Cancel</Button>
        </footer>
    </div>
</template>

嵌套插槽

在父组件里写一个子组件,并且子组件里嵌套着孙子组件,如何将孙子组件的内容也渲染到页面上?

需求:将 导航1 和 内容1 都显示到页面上

父组件的代码

<template>
<div>
    <h1>Tabs组件</h1>
    <Tabs>
        <Tab title="导航1">内容1</Tab>
        <Tab title="导航2">内容2</Tab>
    </Tabs>
</div>
</template>

1.在孙子组件写上插槽

<template>
<div>
    <slot />
</div>
</template>

2.使用context在子组件获取父组件传递的内容,

context.slots.default() 可以获取到父组件传递的标签对象结构

  • 可以使用component 在子组件的模板上将内容渲染,但是只能将内容1,内容2显示到页面上。标签里的title内容显示不出来
<component v-for="(c,index) in defaults" :is="c" :key="index" />
  • 使用forEach 或者map可以遍历到标签对象,这样就可以调用里面的属性了 此时titles里面存储的就是标签里的title数组了,
const titles = defaults.map((tag) => {
            return tag.props.title
        })

子组件完整的代码

<template>
<div>
    <div v-for="(t,index) in titles" :key="index">{{t}}</div>
    <component v-for="(c,index) in defaults" :is="c" :key="index" />
</div>
</template>

<script lang="ts">
import Tab from './Tab.vue'
export default {
    setup(props, context) {
    //获取标签对象数组
        const defaults = context.slots.default()
        //这个可以检查传递的组件是否是孙子组件
        defaults.forEach((tag) => {
            if (tag.type !== Tab) {
                throw new Error('Tabs 子标签必须是Tab')
            }
        })
        //获取标签里的title属性数组
        const titles = defaults.map((tag) => {
            return tag.props.title
        })
        return {
            defaults,
            titles
        }
    }
}
</script>

总结

  • 标签对象属性组.type !== Tab可以判断传递过来的孙子组件是不是Tab类型的
  • context.slots.default()可以获取传递的插槽内容
  • component组件可以渲染出传递的标签
  • 在使用 v-for遍历时要使用:key 但是使用index有时可能会出现bug,这个下回再深究