solt插槽

6 阅读3分钟

一、插槽的核心概念与作用

定义:插槽是 Vue 实现组件内容分发的机制,允许父组件向子组件指定位置插入 HTML 结构,类似“占位符”。
核心作用

  • 实现组件的灵活复用(如布局组件、表单组件);
  • 分离组件逻辑与内容,符合“关注点分离”原则;
  • 结合作用域插槽实现父子组件数据双向流通。

二、Vue 2 与 Vue 3 插槽语法对比表

特性Vue 2 写法Vue 3 写法核心变化
默认插槽<template slot-scope="props"><template #default="props">统一用 v-slot# 前缀,简化语法
具名插槽<template slot="header"><template #header>移除 slot 属性,改用 v-slot:
作用域参数slot-scope="props"v-slot="props"参数接收方式统一
缩写语法#header#header保留 # 缩写,更简洁
参数解构不支持直接解构支持 v-slot="{ user }" 直接解构提升模板可读性

三、具体写法与示例对比

1. 默认插槽(匿名插槽)
<!-- 子组件(通用卡片) -->
<template>
  <div class="card">
    <slot>默认内容(无传入时显示)</slot>
  </div>
</template>

<!-- Vue 2 父组件 -->
<CardComponent>
  <template slot-scope="props">
    <p>父组件传入内容:{{ props.data }}</p>
  </template>
</CardComponent>

<!-- Vue 3 父组件 -->
<CardComponent>
  <template #default="props">
    <p>父组件传入内容:{{ props.data }}</p>
  </template>
</CardComponent>

<!-- Vue 3 简化写法(省略 #default) -->
<CardComponent #="{ data }">
  <p>父组件传入内容:{{ data }}</p>
</CardComponent>
2. 具名插槽(指定位置插入)
<!-- 子组件(布局组件) -->
<template>
  <div class="layout">
    <header>
      <slot name="header">默认头部</slot>
    </header>
    <main>
      <slot>默认主体</slot>
    </main>
    <footer>
      <slot name="footer">默认底部</slot>
    </footer>
  </div>
</template>

<!-- Vue 2 父组件 -->
<LayoutComponent>
  <template slot="header">
    <h1>自定义头部</h1>
  </template>
  <p>自定义主体内容</p>
  <template slot="footer">
    <p>© 2023 版权所有</p>
  </template>
</LayoutComponent>

<!-- Vue 3 父组件 -->
<LayoutComponent>
  <template #header>
    <h1>自定义头部</h1>
  </template>
  <p>自定义主体内容</p>
  <template #footer>
    <p>© 2023 版权所有</p>
  </template>
</LayoutComponent>

<!-- Vue 3 更简洁写法 -->
<LayoutComponent>
  <h1 #header>自定义头部</h1>
  <p>自定义主体内容</p>
  <p #footer>© 2023 版权所有</p>
</LayoutComponent>
3. 作用域插槽(子组件向父组件传数据)
<!-- 子组件(列表项) -->
<template>
  <div class="list-item">
    <slot :item="item" :index="index">
      <span>{{ item.name }}</span>
    </slot>
  </div>
</template>

<script>
export default {
  props: {
    item: Object,
    index: Number
  }
}
</script>

<!-- Vue 2 父组件 -->
<ListItem :item="user" :index="0">
  <template slot-scope="scope">
    <div>
      <span>序号:{{ scope.index + 1 }}</span>
      <span>姓名:{{ scope.item.name }}</span>
    </div>
  </template>
</ListItem>

<!-- Vue 3 父组件 -->
<ListItem :item="user" :index="0">
  <template #default="{ item, index }">
    <div>
      <span>序号:{{ index + 1 }}</span>
      <span>姓名:{{ item.name }}</span>
    </div>
  </template>
</ListItem>

四、核心区别与原理分析

  1. 语法统一化

    • Vue 2 中 slot(具名)与 slot-scope(作用域)是独立语法,易混淆;
    • Vue 3 用 v-slot(可缩写为 #)统一所有插槽场景,参数通过 v-slot="props" 接收,避免语法碎片化。
  2. 参数解构支持

    • Vue 3 允许直接解构插槽参数(如 #default="{ item, index }"),减少模板中的 scope.item 嵌套访问,提升可读性;
    • Vue 2 需通过 slot-scope="scope" 接收后再访问 scope.item
  3. 编译规则变化

    • Vue 3 要求插槽内容必须包裹在 <template> 中(除非是单个元素),否则报错;
    • Vue 2 中可直接在组件标签内写入内容(如 <Card>内容</Card>),但不利于语法统一。
  4. 性能优化

    • Vue 3 的插槽编译结果更高效,减少了运行时的函数生成开销;
    • 作用域插槽的参数传递方式优化,避免不必要的组件更新。

五、问题

1. 问:Vue 3 为什么要改变插槽语法?

  • Vue 2 中 slotslot-scope 共存导致语法混乱(如具名插槽用 slot,作用域插槽用 slot-scope),开发者需记忆多套规则。Vue 3 用 v-slot 统一语法,通过 # 缩写保持简洁,同时支持参数解构,降低学习成本并提升代码可读性。
2. 问:Vue 3 中如何省略默认插槽的写法?
  • <!-- 完整写法 -->
    <Component>
      <template #default="{ data }">
        <p>{{ data }}</p>
      </template>
    </Component>
    
    <!-- 简化写法(省略 <template> 和 #default) -->
    <Component #="{ data }">
      <p>{{ data }}</p>
    </Component>
    
    当插槽为默认插槽时,可直接在组件标签上使用 # 前缀,且无需包裹 <template>(只要内容是单个元素)。
3. 问:作用域插槽在 Vue 2 和 Vue 3 中的本质区别?
    • 本质相同:均通过函数参数传递子组件数据,父组件接收后渲染;
    • 语法差异
      Vue 2 通过 slot-scope 定义参数(如 slot-scope="props"),
      Vue 3 通过 v-slot 接收参数(如 #default="props"),并支持解构(如 #default="{ user }")。