Code前端首页关于Code前端联系我们

Vue3里的slot组件该怎么用?新手能快速搞懂的实用指南

terry 7小时前 阅读数 17 #SEO
文章标签 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>里有enzhja三个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>里留headercontentfooter三个具名插槽,父组件用的时候,想放啥内容就放啥(比如有的弹窗要表单,有的要图片),不用每次改子组件代码。

表格列的自定义渲染

后台管理系统里的<Table>组件,每一列的内容可能需要个性化(比如性别列显示图标,操作列显示按钮组),用作用域插槽,子组件把每一行的数据传给父组件,父组件用v-slot="row"拿到数据后,自定义每一列的渲染方式,表格瞬间灵活起来~

布局组件的灵活组合

写页面布局时,用<PageLayout>组件包含headersidebarmainfooter四个插槽,不同页面(比如首页、详情页)可以自由组合这些区域的内容,不用重复写布局结构,复用性拉满。

组件库的扩展性

像Element Plus、Ant Design Vue这些UI库,很多组件(比如<el-table><a-modal>)都用了slot,让开发者能基于基础组件做个性化定制,不用重复造轮子。

说白了,slot就是给组件“开天窗”——子组件负责逻辑和基础结构,父组件负责个性化内容,分工明确还灵活,项目维护起来更轻松~

最后总结一下:Vue3的slot把语法简化了,但核心还是“占位符传内容”,从单个默认插槽,到多个具名插槽,再到能传数据的作用域插槽、动态切换的动态插槽,不同场景选对应的用法,组件的扩展性和复用性直接起飞~ 新手只要把这几种用法练熟,写组件时再也不会纠结“父组件咋给子组件传结构”的问题啦!

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门