Vue3里的slot组件该怎么用?新手能快速搞懂的实用指南
Vue3里的slot到底是干啥的?
你可以把slot理解成“组件里的占位符”,比如你写了个弹窗组件<Dialog>,里面需要标题、内容、底部按钮这些区域,但这些区域的具体内容(比如标题文字、按钮文案)每个页面用的时候都不一样,这时候slot就派上用场了——在子组件(Dialog)里留好<slot>,父组件用的时候,把想要的内容“塞”进这个占位符里,简单说,slot让父组件能给子组件传递“结构和内容”,而不只是像props那样传递数据。
举个生活化的例子:你点外卖选“套餐”,套餐里的饭盒是子组件,饭盒里预先留了放菜、放饭的格子(slot),商家(父组件)把宫保鸡丁、米饭分别放进对应的格子里,最终你拿到的饭盒就有了定制化的内容~
Vue3的slot和Vue2有啥不一样?
Vue2和Vue3在slot的核心逻辑上没变化(都是传内容的占位符),但语法和使用体验优化了不少:
- 指令统一:Vue2里用
slot属性(父组件传内容时)和slot-scope(作用域插槽),Vue3把这些统一成v-slot指令,还能缩写成,比如Vue2里写<template slot-scope="props">,Vue3要写成<template v-slot="props">或者<template #default="props">(default是默认插槽名)。 - 作用域插槽更简洁:Vue2里子组件传数据给父组件,得写
<slot :data="list"></slot>,父组件用<template slot-scope="scope">{{ scope.data }}</template>;Vue3直接用<template v-slot="scope">{{ scope.data }}</template>,少了“slot-scope”这个专属指令,和普通插槽的v-slot统一了。 - 性能和编译优化:Vue3的编译器对slot处理更高效,尤其是大量插槽场景下,渲染性能比Vue2好一些(这部分不用深究,知道更丝滑就行~)
简单说,Vue3把slot的语法“瘦身”了,学起来更顺,写代码也更简洁。
最基础的单个slot咋用?
单个slot也叫“默认插槽”,步骤特简单:
步骤1:子组件里留占位符
比如写个按钮组件<MyButton>,想让父组件决定按钮里的文字,子组件代码这样写:
<template>
<button class="my-btn">
<!-- 这里放slot,父组件传的内容会替换掉这个位置 -->
<slot></slot>
</button>
</template>
步骤2:父组件里传内容
用的时候,直接把内容包在<MyButton>标签里:
<template> <MyButton>点我提交</MyButton> </template>
这样渲染后,按钮里就会显示“点我提交”,要是父组件没传内容,还能给slot加:
子组件改成:
<slot>默认按钮</slot>
父组件不用传内容时,按钮就显示“默认按钮”,传了就替换掉默认内容~
多个slot(具名插槽)怎么玩?
如果子组件需要多个“自定义区域”(比如弹窗有头部、内容、底部),单个slot不够用,这时候得给slot起名字,也就是具名插槽。
子组件里给slot命名
比如写个<Layout>组件,需要头部、主体、底部三个区域:
<template>
<div class="layout">
<!-- 头部slot,名字叫header -->
<slot name="header"></slot>
<!-- 主体slot,名字叫main(也可以省略name,默认叫default) -->
<slot name="main"></slot>
<!-- 底部slot,名字叫footer -->
<slot name="footer"></slot>
</div>
</template>
父组件里对应名字传内容
父组件要用<template v-slot:名字>(或缩写#名字)来指定内容该往哪个slot里塞:
<template>
<Layout>
<!-- 头部内容,对应name="header"的slot -->
<template v-slot:header>
<h1>这是页面标题</h1>
</template>
<!-- 主体内容,对应name="main"的slot -->
<template #main>
<p>这里是正文内容...</p>
</template>
<!-- 底部内容,对应name="footer"的slot -->
<template #footer>
<button>回到顶部</button>
</template>
</Layout>
</template>
这样每个<template>,会精准跑到子组件对应name的slot位置,实现“哪里需要插哪里”~
作用域插槽是啥?子组件数据咋给父组件用?
有时候子组件里有数据(比如列表数组),但父组件想自定义这部分数据的渲染方式(比如列表项是显示文字还是加图标),这时候得让子组件把数据“传给”父组件,这就是作用域插槽干的事。
子组件传数据给slot
比如子组件<MyList>里有个列表数据listData,想让父组件决定怎么渲染每个列表项:
<template>
<ul>
<li v-for="item in listData" :key="item.id">
<!-- 把item传给父组件,用:item语法(和props传值一样) -->
<slot :item="item"></slot>
</li>
</ul>
</template>
<script setup>
import { ref } from 'vue'
const listData = ref([
{ id: 1, name: '苹果' },
{ id: 2, name: '香蕉' }
])
</script>
父组件接收并自定义渲染
父组件用v-slot="接收的变量"来拿子组件传的数据,然后自定义结构:
<template>
<MyList>
<!-- 默认插槽(没写name就是default),接收子组件传的item -->
<template v-slot="slotProps">
<!-- slotProps里包含子组件传的item -->
<span>{{ slotProps.item.name }} - 好吃!</span>
</template>
</MyList>
</template>
要是用具名的作用域插槽(比如子组件slot有name),写法是<template #name="slotProps">,原理一样~ 这样父组件能拿到子组件的数据,想怎么渲染就怎么渲染,灵活性拉满!
动态插槽是啥场景用?
动态插槽就是插槽的名字由变量决定,场景比如“根据用户选择切换不同的布局块”或者“多语言切换时,不同语言对应不同的插槽内容”。
子组件留多个具名插槽
比如子组件<DynamicPanel>里有en、zh、ja三个slot,对应不同语言的内容:
<template>
<div class="panel">
<slot name="en"></slot>
<slot name="zh"></slot>
<slot name="ja"></slot>
</div>
</template>
父组件用变量控制插槽名
父组件里用v-slot:[变量名]来动态切换要渲染的插槽:
<template>
<div>
<!-- 选择语言的下拉框,改变currentLang变量 -->
<select v-model="currentLang">
<option value="en">English</option>
<option value="zh">中文</option>
<option value="ja">日本語</option>
</select>
<!-- 动态插槽:插槽名由currentLang决定 -->
<DynamicPanel>
<template v-slot:[currentLang]>
<!-- 根据currentLang显示对应内容 -->
<p v-if="currentLang === 'en'">Hello!</p>
<p v-else-if="currentLang === 'zh'">你好!</p>
<p v-else>こんにちは!</p>
</template>
</DynamicPanel>
</div>
</template>
<script setup>
import { ref } from 'vue'
const currentLang = ref('zh') // 默认中文
</script>
这样用户切换语言时,插槽名跟着变,对应的内容也自动切换,特别适合需要“动态切换模板”的场景~
实际项目里slot能解决哪些痛点?
slot在实际开发中贼实用,举几个常见场景:
通用组件的定制化内容
比如公司所有页面的弹窗<BaseDialog>、内容、按钮每次都不一样,用slot的话,子组件<BaseDialog>里留header、content、footer三个具名插槽,父组件用的时候,想放啥内容就放啥(比如有的弹窗要表单,有的要图片),不用每次改子组件代码。
表格列的自定义渲染
后台管理系统里的<Table>组件,每一列的内容可能需要个性化(比如性别列显示图标,操作列显示按钮组),用作用域插槽,子组件把每一行的数据传给父组件,父组件用v-slot="row"拿到数据后,自定义每一列的渲染方式,表格瞬间灵活起来~
布局组件的灵活组合
写页面布局时,用<PageLayout>组件包含header、sidebar、main、footer四个插槽,不同页面(比如首页、详情页)可以自由组合这些区域的内容,不用重复写布局结构,复用性拉满。
组件库的扩展性
像Element Plus、Ant Design Vue这些UI库,很多组件(比如<el-table>、<a-modal>)都用了slot,让开发者能基于基础组件做个性化定制,不用重复造轮子。
说白了,slot就是给组件“开天窗”——子组件负责逻辑和基础结构,父组件负责个性化内容,分工明确还灵活,项目维护起来更轻松~
最后总结一下:Vue3的slot把语法简化了,但核心还是“占位符传内容”,从单个默认插槽,到多个具名插槽,再到能传数据的作用域插槽、动态切换的动态插槽,不同场景选对应的用法,组件的扩展性和复用性直接起飞~ 新手只要把这几种用法练熟,写组件时再也不会纠结“父组件咋给子组件传结构”的问题啦!
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网


