slot在vue2和vue3的写法汇总

Daotin 于 2024-06-20 发布 编辑
  1. 插槽的定义
  2. 插槽的使用
  3. 作用域插槽
  4. $slots 和 $scopedSlots

插槽的定义

1、组件中默认插槽的定义:

<a :href="url">
  <slot></slot>
</a>

2、具名插槽的定义:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

插槽的使用

1、默认插槽的使用

<navigation-link url="/profile">
  Your Profile
</navigation-link>

2、具名插槽的使用

<!-- vue2.6.0之前 -->
<base-layout>
  <template slot="header">
    <h1>Here might be a page title</h1>
  </template>

  <!-- 隐藏默认插槽 slot="default" -->
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template slot="footer">
    <p>Here's some contact info</p>
  </template>
</base-layout>


<!-- vue2.6.0之后(包括vue3) -->
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <!-- 隐藏默认插槽 v-slot:default -->
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

注意:v-slot 只能添加在 <template> 上,(例外:当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。) 但是,slot-scope 可以直接用于非 <template> 元素 (包括组件)。

例如:

<current-user v-slot="slotProps">
  
</current-user>


<slot-example>
  <span slot-scope="slotProps">
    
  </span>
</slot-example>

作用域插槽

在插槽中,如果想使用定义插槽的组件的数据:

比如current-user组件,

<span>
  <slot></slot>
</span>

我们可能想换掉备用内容,用名而非姓来显示。如下:

<current-user>
  
</current-user>

我们需要在插槽内容将user暴露出来:

<span>
  <slot :user="user">
    
  </slot>
</span>

然后才能使用:

<!-- vue2.6.0之前 -->
<current-user>
  <template slot-scope="slotProps">
    
  </template>
</current-user>

<!-- vue2.6.0之后(包括vue3) -->
<current-user>
  <template v-slot="slotProps">
    
  </template>
</current-user>

当然,我们也可以采用解构赋值重命名的写法:

<!-- 解构赋值 -->
<current-user v-slot="{ user }">
  
</current-user>

<!-- 解构赋值+重命名 -->
<current-user v-slot="{ user: person }">
  
</current-user>

<!-- 解构赋值+插槽默认值 -->
<current-user v-slot="{ user = { firstName: 'daotin' } }">
  
</current-user>

当然,v-slot也可以采用缩写的写法:

跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header:

<!-- 注意:#="{ user } 会触发一个警告 -->
<current-user #default="{ user }">
  
</current-user>

$slots 和 $scopedSlots

1、$slots 一个表示父组件所传入插槽的对象。通常用于手写render渲染函数,但也可用于检测是否存在插槽。

可以直接通过 $slots.slotName 访问对应的插槽内容,其中 slotName 是插槽的名字。如果插槽是默认插槽(无名字),则通过 $slots.default 访问。

2、$scopedSlots : 作用域插槽允许子组件将数据传递到它的插槽内容中,这些内容是由父组件提供的。这种机制允许父组件访问到从子组件传来的数据,以便根据这些数据动态渲染插槽内容。

使用和目的:

示例:

<!-- ParentComponent.vue -->
<template>
  <UserCard>
    <!-- 默认插槽 -->
    <template v-slot:default>
      <p>Welcome to the user card!</p>
    </template>
    
    <!-- 具名插槽 -->
    <template v-slot:header>
      <h1>User Information</h1>
    </template>
    
    <!-- 作用域插槽 -->
    <template v-slot:details="slotProps">
      <p>Name: </p>
      <p>Email: </p>
    </template>
  </UserCard>
</template>

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

export default {
  components: {
    UserCard
  }
}
</script>



<!-- UserCard.vue -->
<template>
  <div>
    <div v-if="$scopedSlots.header">
      <!-- 只有在父组件提供了header插槽时才渲染 -->
      <slot name="header"></slot>
    </div>
    <div>
      <!-- 总是渲染默认插槽 -->
      <slot></slot>
    </div>
    <div v-if="$scopedSlots.details">
      <!-- 只有在父组件提供了details插槽时才渲染 -->
      <slot name="details" :user="user"></slot>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: {
        name: 'John Doe',
        email: 'john@example.com'
      }
    };
  },
  mounted() {
    // 访问默认插槽内容
    console.log(this.$slots.default);  // 包含 <template> 标签中的内容VNode数组
    
    // 访问具名插槽内容
    console.log(this.$slots.header);  // 包含 <h1>User Information</h1>:VNode数    
    // 访问作用域插槽内容
    const scopedSlotContent = this.$scopedSlots.details({ user: this.user });
    console.log(scopedSlotContent);  // // VNode数组,包含作用域插槽 'details' 的内容
  }
}
</script>