【Vue3基础】Vue3 Slot

本文介绍了Vue3中插槽的概念和用法,包括基本的插槽使用,如何插入内容,以及插槽的默认内容。接着详细讲解了具名插槽的使用,如何通过v-slot向特定插槽添加内容。此外,还讨论了动态插槽名和插槽的作用域问题,特别是作用域插槽如何实现父组件访问子组件的数据。最后,通过示例展示了默认插槽和具名插槽的作用域传值方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Vue3 Slot

1.基本使用

顾名思义,插槽的作用就是:在指定的地方有一个槽,可以给我们插入一些东西。

在Vue中,插槽 slot 通常用于两个父子组件之间,其中最为常见的应用就是 UI 组件库,例如:Ant design、ELement等等,它们的弹窗组件、列表组件等其中的部分内容是可以自定义的,这就是使用了插槽来实现的!

下面,我们通过一个实例来学习插槽的使用。

首先在项目中新建一个子组件childCom.vue,其代码如下:

<template>
  <div class="child-box">
    <p>我是子组件</p>
    <!-- 插槽 -->
    <slot></slot>
  </div>
</template>
<style>
.child-box {
  display: flex;
  flex-direction: column;
  align-items: center;
}
</style>

然后在根组件App.vue中引用该组件:

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <child></child>
  </div>
</template>

<script>
import child from './components/childCom.vue'

export default {
  name: 'App',
  components: {
    child,
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

效果如下:
在这里插入图片描述
这里我们通过添加<slot></slot>标签,在 child 组件内部挖了一个槽出来,我们接下来就可以往这个槽里面放置一些内容。

那么,如何插入内容?

如果我们在父组件中,向<child></child>之间插入一点内容,代码如下:

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <child>
      <div>这里是自父组件插入的内容</div>
    </child>
  </div>
</template>

效果如下:
在这里插入图片描述
可以看到,在<child></child>之间插入的内容占据了原本<slot></slot>标签的位置!所以,这里我们在父组件中添加的div便就是我们要添加的东西,子组件中slot标签被替换为了我们插入的div元素。这就是插槽的最基本使用。

总结一下:

  • slotVue3 中的内置标签。
  • slot 相当于给子组件挖出了一个槽,可以用来填充内容。
  • 父组件中调用子组件时,子组件标签之间的内容元素就是要放置的内容,它会把 slot 标签替换掉。

2.插槽默认内容

插槽可以类比一个占位符,当父组件填入了内容,会自动占据 slot 标签的位置,但是,如果父组件中没有填入任何内容,此时 slot 标签位置应该渲染什么内容呢?

实际上,这种情况在很多场景下都会出现,比如前面说到的 UI 组件库的弹窗组件,当我们没有传入自定义的头部、底部等内容,弹窗仍然会有默认的样式效果!这就是用 slot 默认内容来实现的。

修改子组件代码如下:

<template>
<div class="child-box">
    <p>子组件</p>
    <!-- 插槽 -->
    <slot>
        <p>默认内容</p>
    </slot>
</div>
</template>
<style>
.child-box {
display: flex;
flex-direction: column;
align-items: center;
}
</style>

然后在父组件中,我们不传入任何内容:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child></child>
</template>

效果如下:
在这里插入图片描述
可以看到,渲染的是我们设定好的默认内容!

slot 标签内的内容就是默认内容,也就是当父组件没有传递给子组件内容时,子组件就会默认渲染 slot 内部的内容,但是 slot 标签是不会渲染出来的!

3.具名插槽

但是,在较为复杂的业务场景中,往往子组件内部需要不止一个插槽,例如前面说到的 UI 组件库的弹窗组件,其允许调用者同时插入headercontentfooter等等自定义内容。

此时,子组件内部不可能会只有一个插槽,但是如果有多个插槽,应该如何区分呢?或者说应该如何进行渲染呢?

3.1 使用

这个时候为了区分插槽与内容的对应关系,我们可以分别给 slot 和内容都加上一个名字,插入插槽的时候大家按照名字区分好就可以了。

如何为插槽加上名称?

Vue中提供了一个属性:name,我们可以在其中设置插槽的名称:

<slot name="slot1">...</slot>

所以,接下来,我们给 childCom 组件添加上多个 slot,并且给每个 slot 取上一个名字。

<template>
  <div class="child-box">
    <p>我是子组件</p>
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot>
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

上段代码中我们添加了 3 个 slot 插槽,并且给其中两个 slot 标签添加了一个 name 属性,也就是每个插槽的名字。需要注意的是,上段代码中有一个插槽我们没有添加 name 属性,这个时候 Vue 会隐式的将这个插槽命名为“default”,接下来就是我们父组件 App.vue 添加内容了。

那么,如何向指定名称的插槽中插入内容?

Vue中同样提供了一个指令:v-slot

<template v-slot="header">
    ...
</template>
<!-- 简写形式 -->
<template #header>
    ...
</template>

但是,需要注意的是,v-slot指令仅能用于<template></template>上!

所以我们接下来就可以使用这种方式在父组件中向插槽中添加内容了:

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <child>
      <template v-slot:header>
        <div>我是 header:{{ message }}</div>
      </template>
      <div>我没有名字:{{ message }}</div>
      <template v-slot:footer>
        <div>我是 footer:{{ message }}</div>
      </template>
    </child>
  </div>
</template>

效果如下:
在这里插入图片描述
可以看出,我们传入的内容都渲染到了对应的插槽内,没有命名的插槽渲染了我们传入的未添加指令的内容。

3.2 默认插槽与具名插槽混合使用

当一个子组件中既有具名插槽,又有默认插槽时,该如何渲染呢?

前面我们说默认插槽会被隐式的命名为 default,所以我们传入内容时可以将插槽名字改为 defalut 即可。

修改父组件:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child>
    <template #header>
      <div>我是 header</div>
    </template>
    <template #default>
      <div>我没有名字</div>
      <div>我没有名字</div>
      <div>我没有名字</div>
    </template>
    <template #footer>
      <div>我是 footer</div>
    </template>
  </child>
</template>

效果如下:
在这里插入图片描述

4.动态插槽名

在上面的内容中,所有的插槽命名都是写死的,但实际上我们可以动态地给插槽命名,以适应更多的业务场景。

代码如下:

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
  <!-- 缩写为 -->
  <template #[dynamicSlotName]>
    ...
  </template>
</base-layout>

这里就是在父组件中,在传入内容时采用动态的插槽名。

5.插槽的作用域问题

通过上面对于插槽的使用,我们可以发现,插槽实际上与父子组件通信有一些类似,只不过插槽中传递的模板内容。那么既然涉及到传值,就会涉及到一个作用域的问题。看下面这段代码:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child>
    <div>{{ message }}</div>
  </child>
</template>
 
 
<script>
import Child from "./child.vue";
...
const message = "这里是一条message!";
</script>

上段代码中 message 是我们在父组件中定义的数据,但是在我们的子组件 child 中渲染了出来,说明子组件中的插槽是可以访问到父组件中的数据作用域的,但是反过来是不行的,因为我们无法通过插槽拿到子组件的数据。

总结来说,有两点:

  • 插槽内容可以访问到父组件的数据作用域,就好比上述中的 message 是父组件的。
  • 插槽内容无法访问到子组件的数据,就好比上述 App.vue 中的插槽内容拿不到子组件 child 的数据。

6.作用域插槽

上面说过,父组件中的插槽无法获取到子组件中的数据,但是,在实际开发中,有一些业务需求就是要求在父组件的插槽内容中获取子组件的数据,那此时应该如何处理呢?

Vue中同样也为此提供了相应的功能:插槽作用域传值

6.1 默认插槽作用域传值

先来看默认插槽如何传值

首先在childCom组件中,在slot标签上通过 props 的形式附带一个值

<template>
  <div class="child-box">
    <p>我是子组件</p>
    <slot text="我是子组件小猪课堂" :count="1"></slot>
  </div>
</template>

在父组件中,通过v-slot来接收 props:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child v-slot="slotProps">
    <div>{{ slotProps.text }}---{{ slotProps.count }}</div>
  </child>
</template>

效果如下:
在这里插入图片描述
注意,这里的slotProps 的名字是可以任意取的,它是一个对象,包含了所有传递过来的数据。而这些子组件传递过来的数据只能在子组件这个标签内使用

另外,我们都知道,对象是可以解构的,所以我们在父组件中可以直接用解构的形式来获取数据:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child v-slot="{ text, count }">
    <div>{{ text }}---{{ count }}</div>
  </child>
</template>
6.2 具名插槽作用域传值

了解了默认插槽的作用域传值之后,具名插槽的作用域传值就比较简单了,只不过是将名称与解构混用就行了。

首先在childCom组件中:

<template>
  <div class="child-box">
    <p>我是子组件</p>
    <slot name="header" text="我是子组件小猪课堂" :count="1"></slot>
  </div>
</template>

在父组件中,通过v-slot来接收 props:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child #header="{ text, count }">
    <div>{{ text }}---{{ count }}</div>
  </child>
</template>

当然使用v-slot:header="xxx"也是可以的!

总结

插槽的作用非常广泛,学好插槽对我们的项目开发有着非常大的帮助,当然,想要非常优雅的使用插槽,还是需要费一些功夫的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值