Vue3之插槽

发布时间:2023年12月25日

前言

之前的文章里介绍了vue3中父传子props方法可以传递js中任意类型的数据。那么如何向子组件中传入模版呢,很多时候组件里面需要渲染一些自定义的模块,根据不同的场景显示不同的内容,此时传递模版就更方便,这就要用到slot也就是插槽了。文中的例子也都是使用vue3的语法。

插槽

插槽(slot)是一种非常强大和灵活的机制,用于在组件中传递内容。在组件中通过插槽定义模板,然后在使用的时候填充具体的内容。
在组件中,你可以使用 元素来定义插槽的出口,表示一个可插入内容的位置。在父组件中,可以通过插入内容到这个插槽来填充它。

组件模板:

<template>
  <div>
    <h1>组件</h1>
    <slot></slot>
  </div>
</template>

使用

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

<template>
  <SComponent>
    <p>父组件的内容将插入到子组件的插槽中。</p>
  </SComponent>
</template>

</script>

渲染作用域

插槽中的内容可以访问父组件中的数据和方法。这意味着插槽内容在父组件的作用域内进行渲染,可以使用父组件的数据和方法。
就比如下面的例子里面,这里两个插值表达式渲染的内容是一样的。

<script setup>
import { ref } from 'vue';
import SComponent from './SComponent.vue';
const title = ref("标题");
</script>

<template>
  <div>{{ title }}</div>
  <SComponent>
    <p>{{ title }}</p>
  </SComponent>
</template>

</script>

但是插槽内容无法访问子组件的数据。Vue 模板中的表达式只能访问其定义时所处的作用域,这和 JavaScript 的词法作用域规则是一致的。

默认插槽

很多时候不需要传入内容,默认就显示的模块,叫做默认插槽。注意:一个组件里面只能定义一个默认插槽
比如一个公共组件SubmitButton.vue

<template>
  <botton>
    <slot>
      确定
    </slot>
  </button>
</template>

使用:在没有传入内容时,默认就展示 确定。如果父组件传递了内容就使用传递的。

<SubmitButton />

此时就会显示保存

<SubmitButton>保存</SubmitButton>

具名插槽

有时候一个组件里面需要多个插槽,为了确定渲染的内容不出错,就需要给占位的槽位取个名字,使用时根据名字就能分别渲染出来具体的内容了。

比如:SlotComponent.vue

<template>
  <div>
    <h1>组件</h1>
    // 具名插槽
    <slot name="header"></slot>
    // 默认插槽
    <slot></slot>
  </div>
</template>

使用:需要通过v-slot指令给插槽传递内容,v-slot 有对应的简写 #,下面的<template v-slot:header>也就等同于<template #header>

<template>
  <slot-component>
    <template v-slot:header>
      <p>这是头部插槽</p>
    </template>
    <p>这是默认内容</p>
  </slot-component>
</template>

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

当然可以有多个不同名字的插槽,特点就是使用了name属性,没有使用name属性的就是默认插槽。用法如上。

作用域插槽

作用域插槽允许子组件向插槽传递数据,使插槽内容可以使用子组件中的数据。虽然上面说到了插槽的内容无法访问到子组件的状态。但是某些场景还是需要使用子组件内部的数据。可以像对组件传递 props 那样,向一个插槽的出口上传递 attributes:

<template>
  <div>
    <h1>组件</h1>
    <slot :data="someData"></slot>
  </div>
</template>

<script setup>
import { ref } from 'vue';
const someData = ("一些内容");
</script>

使用:

<template>
  <slot-component>
    <template v-slot="slotProps">
      <p>{{ slotProps.data }}</p>
    </template>
  </slot-component>
</template>

<script>
import SlotComponent from './SlotComponent.vue';
</script>

子组件传递的参数也支持结构语法,上面的代码等同于:

<template>
  <slot-component>
    <template v-slot="{ data }">
      <p>{{ data }}</p>
    </template>
  </slot-component>
</template>
具名插槽使用
<template>
  <div>
    <h1>组件</h1>
    <slot name="xxx" :data="someData"></slot>
  </div>
</template>

<script setup>
import { ref } from 'vue';
const someData = ("一些内容");
</script>

使用:可以使用v-slot:xxx="props"也可以简写#xxx="props"

<template>
  <slot-component>
    <template #xxx="{ data }">
      <p>{{ data }}</p>
    </template>
  </slot-component>
</template>

在同时使用具名插槽和默认插槽时应该用<template>包裹,这样更明确props作用域。

<template>
  <div>
    <h1>组件</h1>
    <slot :message="someData"></slot>
    <slot name="footer"></slot>
  </div>
</template>

<script setup>
import { ref } from 'vue';
const someData = ("一些内容");
</script>

使用:


<template>
  <MyComponent>
    <!-- 使用显式的默认插槽 -->
    <template #default="{ message }">
      <p>{{ message }}</p>
    </template>

    <template #footer>
      <p>Here's some contact info</p>
    </template>
  </MyComponent>
</template>

注意事项:

  • 插槽名称:作用域插槽使用 v-slot 指令,并通过 v-slot 指定一个变量名,用于接收子组件传递的数据。确保你理解如何正确使用插槽名称。

    <!-- 在这个例子中,插槽名称为 "data" -->
    <template v-slot:data="{ prop1, prop2 }">
      <!-- 使用 prop1 和 prop2 -->
    </template>
    
  • 作用域冲突: 当插槽内使用的变量名与当前作用域中的变量名相同时,可能会引发冲突。避免使用相同的变量名,或者使用修饰符如 v-slot:data="{ data: slotData }" 来避免冲突。

  • 清晰的传递数据:在使用作用域插槽时,确保数据的传递清晰明了,这样维护和理解代码将更加容易。

  • 适度使用: 不是所有的场景都需要使用作用域插槽,因此请根据具体情况决定是否使用。对于简单的插槽需求,普通插槽已经足够。

  • 维护性: 尽管作用域插槽非常强大,但在一些情况下可能使模板变得更加复杂。在考虑可维护性时,确保代码结构清晰,易于理解。

文章来源:https://blog.csdn.net/study_way/article/details/135183394
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。