Vue 插槽极简实战手册:三类插槽核心用法

vue 496849654@qq.com 8小时前 26次浏览

Vue 插槽(Slot)的本质是‌位置占位 + 内容分发‌。它解决了组件复用中“结构相似但内容不同”的痛点,
避免了通过大量 Props 传递 HTML 字符串导致的维护困难和 XSS 风险。
以下是默认插槽、具名插槽和作用域插槽的核心用法与实战指南。


1. 默认插槽(Default Slot)

‌核心场景‌:组件只有一个主要区域需要自定义,或者作为其他插槽的“兜底”内容。
‌子组件(挖坑)‌:使用 标签占位。可以设置默认后备内容,当父组件未传入内容时显示。
‌父组件(填坑)‌:直接在子组件标签内部写入 HTML 结构。

<!-- 子组件 BaseCard.vue -->
<template>
  <div class="card">
    <div class="card-body">
      <!-- 如果父组件没传内容,显示“暂无数据” -->
      <slot>暂无数据</slot>
    </div>
  </div>
</template>

<!-- 父组件 App.vue -->
<template>
  <BaseCard>
    <p>这是父组件传入的自定义内容</p>
  </BaseCard>
  
  <BaseCard /> 
  <!-- 显示默认后备内容:“暂无数据” -->
</template>

2. 具名插槽(Named Slots)

核心场景‌:一个组件内有多个区域需要独立定制(如弹窗的头部、主体、底部)。
子组件(挖多坑)‌:给<slot> 添加 name 属性区分不同区域。
‌父组件(对号入座)‌:使用 <template v-slot:名字> 或简写 <template #名字>。‌
注意:v-slot 指令只能用在 <template> 标签或组件根标签上,
不能直接用在普通 HTML 标签(如 <div>)上。

<!-- 子组件 Modal.vue -->
<template>
  <div class="modal">
    <header>
      <slot name="header">默认标题</slot>
    </header>
    <main>
      <slot></slot> <!-- 匿名插槽,等价于 name="default" -->
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<!-- 父组件 App.vue -->
<template>
  <Modal>
    <!-- 简写语法 #header 等价于 v-slot:header -->
    <template #header>
      <h3>订单详情</h3>
    </template>

    <!-- 默认插槽内容,无需 template 包裹也可,但推荐包裹以保持清晰 -->
    <p>订单具体内容...</p>

    <template #footer>
      <button>取消</button>
      <button>确认</button>
    </template>
  </Modal>
</template>

3. 作用域插槽(Scoped Slots)

核心场景‌:‌子组件拥有数据,但父组件决定如何渲染这些数据‌。常见于表格列定制、列表项自定义渲染。
子组件(传数据)‌:在 <slot> 标签上通过绑定属性(:prop="data")将内部数据暴露出去。
父组件(收数据)‌:通过 v-slot="params" 接收数据对象,并通过解构 { prop } 直接使用。

<!-- 子组件 UserList.vue -->
<template>
  <ul>
    <li v-for="user in users" :key="user.id">
      <!-- 将 user 对象暴露给父组件 -->
      <slot :user="user" :index="user.id">
        {{ user.name }} <!-- 默认渲染方式 -->
      </slot>
    </li>
  </ul>
</template>

<script setup>
const users = [
  { id: 1, name: '张三', role: 'Admin' },
  { id: 2, name: '李四', role: 'User' }
]
</script>

<!-- 父组件 App.vue -->
<template>
  <UserList>
    <!-- 接收子组件传来的数据,解构出 user -->
    <template #default="{ user }">
      <span class="name">{{ user.name }}</span>
      <span class="badge" v-if="user.role === 'Admin'">管理员</span>
    </template>
  </UserList>
</template>

快速避坑与最佳实践

‌语法限制‌:v-slot 必须写在 <template> 标签上(除非是独占默认插槽且无其他具名插槽时可直接写在组件标签上,
但为了统一规范,建议始终使用 <template>)。
‌名称匹配‌:具名插槽的 name 必须严格匹配。
子组件定义 name="header",父组件必须用 #header 或 v-slot:header。
‌解构命名‌:作用域插槽中,父组件接收的参数名(如 { user })可以是任意合法的变量名,只要对应子组件绑定的属性名即可。例如子组件传 :item="data",父组件可以写 v-slot="{ item }"。
‌默认内容优先级‌:如果父组件提供了插槽内容,子组件< slot> 标签内的默认内容将被完全替换;如果父组件未提供,则显示子组件的默认内容。

选型指南

插槽类型 核心能力 典型场景
‌默认插槽‌ 单区域内容分发 按钮文本、卡片主体、简单容器
‌具名插槽‌ 多区域独立定制 弹窗(头/体/脚)、页面布局、复杂表单
‌作用域插槽‌ 子传父数据 + 自定义渲染 表格列自定义、列表项渲染、动态图表

css315 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Vue 插槽极简实战手册:三类插槽核心用法
喜欢 (1)