vue3中slot,template #名称 的详细说明和具体示例

在 Vue3 中,slot(插槽)是组件间传递内容的核心方式,template #名称template v-slot:名称语法糖,用于绑定具名插槽。下面我会从基础到进阶,详细讲解用法并给出可直接运行的示例。

一、核心概念先理清

  1. 插槽的作用:让组件的部分内容由使用组件的父组件自定义,实现组件内容的灵活复用。
  2. # 语法糖#xxx 等价于 v-slot:xxx,只能用在 <template> 标签上(或组件标签本身,仅限默认插槽)。
  3. 分类
    • 具名插槽:有明确名称的插槽(如 #header#content),用于组件内多位置自定义内容。
    • 默认插槽:无名称的插槽(#default,可省略),组件内未命名的插槽位置。
    • 作用域插槽:插槽可以接收子组件传递的数据(核心:子传父,父组件自定义渲染逻辑)。

二、具体用法 + 完整示例

1. 基础:具名插槽(template #名称 核心用法)

步骤1:定义带具名插槽的子组件(MySlot.vue)

子组件通过 <slot name="xxx"> 定义插槽位置,name 对应父组件的 #xxx

vue 复制代码
<!-- MySlot.vue -->
<template>
  <div class="slot-container">
    <!-- 头部插槽 -->
    <div class="header">
      <slot name="header">默认头部内容(父组件没传则显示这个)</slot>
    </div>
    
    <!-- 内容插槽 -->
    <div class="content">
      <slot name="content">默认内容</slot>
    </div>
    
    <!-- 底部插槽(默认插槽,省略name) -->
    <div class="footer">
      <slot>默认底部内容</slot>
    </div>
  </div>
</template>

<style scoped>
.slot-container {
  border: 1px solid #ccc;
  padding: 20px;
  width: 400px;
  margin: 20px auto;
}
.header { border-bottom: 1px solid #eee; padding-bottom: 10px; }
.content { padding: 10px 0; }
.footer { border-top: 1px solid #eee; padding-top: 10px; color: #666; }
</style>

步骤2:父组件使用 template #名称 传递内容

父组件通过 <template #插槽名> 给对应插槽传递自定义内容:

vue 复制代码
<!-- 父组件 App.vue -->
<template>
  <div>
    <h2>具名插槽示例</h2>
    <MySlot>
      <!-- 绑定header插槽:#header 等价于 v-slot:header -->
      <template #header>
        <h3>自定义的头部标题</h3>
      </template>

      <!-- 绑定content插槽 -->
      <template #content>
        <p>这是自定义的内容区域,可放任意HTML/组件</p>
        <button>自定义按钮</button>
      </template>

      <!-- 默认插槽:#default 可省略,直接写内容 -->
      <template #default>
        <p>自定义的底部内容</p>
      </template>
      <!-- 简化写法:默认插槽无需template,直接写内容 -->
      <!-- <p>自定义的底部内容</p> -->
    </MySlot>
  </div>
</template>

<script setup>
import MySlot from './components/MySlot.vue';
</script>

效果

  • 头部显示「自定义的头部标题」(替换了子组件的默认头部);
  • 内容区显示自定义的文字+按钮;
  • 底部显示「自定义的底部内容」。
2. 进阶:作用域插槽(带参数的 template #名称

作用域插槽的核心是子组件向插槽传递数据 ,父组件通过 #名称="参数" 接收,再自定义渲染逻辑。

步骤1:子组件定义带数据的插槽(MyScopeSlot.vue)

通过 slot 标签的属性传递数据(如 :list="list"):

vue 复制代码
<!-- MyScopeSlot.vue -->
<template>
  <div class="scope-slot">
    <h4>子组件的列表数据</h4>
    <!-- 具名作用域插槽:向父组件传递list数据 -->
    <slot name="list" :list="list" :title="'用户列表'">
      <!-- 默认渲染逻辑(父组件没自定义则显示) -->
      <ul>
        <li v-for="item in list" :key="item.id">{{ item.name }}</li>
      </ul>
    </slot>
  </div>
</template>

<script setup>
// 子组件的数据源
const list = [
  { id: 1, name: '张三', age: 20 },
  { id: 2, name: '李四', age: 22 },
  { id: 3, name: '王五', age: 24 },
];
</script>

步骤2:父组件接收并自定义渲染(App.vue)

通过 #list="slotProps" 接收子组件传递的参数(slotProps 是自定义名称,也可解构):

vue 复制代码
<!-- 父组件 App.vue -->
<template>
  <div>
    <h2>作用域插槽示例</h2>
    <MyScopeSlot>
      <!-- 方式1:完整接收参数 -->
      <!-- <template #list="slotProps">
        <div>
          <h5>{{ slotProps.title }}</h5>
          <table border="1">
            <tr v-for="item in slotProps.list" :key="item.id">
              <td>{{ item.id }}</td>
              <td>{{ item.name }}</td>
              <td>{{ item.age }}</td>
            </tr>
          </table>
        </div>
      </template> -->

      <!-- 方式2:解构参数(推荐,更简洁) -->
      <template #list="{ list, title }">
        <div>
          <h5>{{ title }}</h5>
          <table border="1" cellpadding="5">
            <tr>
              <th>ID</th>
              <th>姓名</th>
              <th>年龄</th>
            </tr>
            <tr v-for="item in list" :key="item.id">
              <td>{{ item.id }}</td>
              <td>{{ item.name }}</td>
              <td>{{ item.age }}</td>
            </tr>
          </table>
        </div>
      </template>
    </MyScopeSlot>
  </div>
</template>

<script setup>
import MyScopeSlot from './components/MyScopeSlot.vue';
</script>

效果

父组件接收到子组件的 listtitle,并将原本的列表渲染成了表格(替换了子组件的默认列表渲染)。

3. 特殊场景:默认插槽的语法糖简化

如果只有默认插槽,可直接在组件标签上用 #default(或省略),甚至直接绑定参数:

vue 复制代码
<!-- 简化写法:默认插槽 -->
<MyScopeSlot #default="{ list }">
  <ul>
    <li v-for="item in list" :key="item.id">{{ item.name }} - {{ item.age }}岁</li>
  </ul>
</MyScopeSlot>

<!-- 更简化:直接写在组件标签上(仅限默认插槽) -->
<MyScopeSlot v-slot="{ list }">
  <p>默认插槽简化写法:{{ list[0].name }}</p>
</MyScopeSlot>

三、注意事项

  1. #v-slot: 的语法糖,只能用在 <template> 标签上(默认插槽可例外,写在组件标签上);
  2. 具名插槽必须匹配子组件 slotname 属性,否则会渲染默认内容;
  3. 作用域插槽的参数可以解构,也可以重命名(如 #list="{ list: userList }");
  4. Vue3 中 slotslot-scope 已废弃,统一使用 v-slot(或 #)。

总结

  1. template #名称template v-slot:名称 的语法糖,用于绑定具名插槽,核心是父组件向子组件指定位置传递自定义内容;
  2. 作用域插槽通过 #名称="参数" 接收子组件传递的数据,实现「子传父+父自定义渲染」;
  3. 默认插槽可省略 #default,直接写内容,作用域插槽的参数支持解构,简化代码。

通过插槽(尤其是 # 语法糖),你可以灵活定制组件的内容,是 Vue 组件封装中最常用的技巧之一。

相关推荐
南篱2 小时前
前端必看:一口气搞懂跨域是什么、为什么、怎么解决
前端·javascript·面试
qq_406176142 小时前
Vue 插槽与组件传参:从入门到精通
前端·javascript·vue.js
张雨zy2 小时前
Vue 的 v-if 与 v-show,Android 的 GONE 与 INVISIBLE
android·前端·vue.js
xjf77112 小时前
Vue转TypeDOM的AI训练方案
前端·vue.js·人工智能·typedom
JamesYoung79712 小时前
第八部分 — UI 表面 sidePanel (如使用) + UX约束
前端·javascript·ui·ux
前端小趴菜052 小时前
Day.js基本使用
vue.js·dayjs
wuhen_n2 小时前
shallowRef 与 shallowReactive:浅层响应式的妙用
前端·javascript·vue.js
wuhen_n2 小时前
事件监听器销毁完全指南:如何避免内存泄漏?
前端·javascript·vue.js
旷世奇才李先生2 小时前
066基于java的中医养生系统-springboot+vue
java·vue.js·spring boot