Vue3中slot插槽使用方式

news2025/2/26 7:22:31

一文搞懂Vue3中slot插槽的使用!

使用 Vue 的小伙伴相信你一定使用过插槽,如果你没有用过,那说明你的项目可能不是特别复杂。插槽(slot)可以说在一个 Vue 项目里面处处都有它的身影,比如我们使用一些 UI 组件库的时候,我们通常可以使用插槽来自定义我们的内容。

1.插槽基本使用

插槽的用途就和它的名字一样:有一个缺槽,我们可以插入一些东西。

插槽 slot 通常用于两个父子组件之间,最常见的应用就是我们使用一些 UI 组件库中的弹窗组件时,弹窗组件的内容是可以让我们自定义的,这就是使用了插槽的原理。

我们在项目中新建一个 child.vue 文件,用来当作子组件,它的代码也非常的简单。

child.vue 代码如下:

<template>
  <div class="child-box">
    <p>我是子组件</p>
    <!-- 插槽 -->
    <slot></slot>
  </div>
</template>
<style>
.child-box {
  display: flex;
  flex-direction: column;
  align-items: center;
}
</style>

然后我们直接在 App.vue 引用该子组件,代码如下:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child></child>
</template>


<script setup lang="ts">
import Child from "./child.vue";
</script>

输出结果:

child 子组件代码非常的简单,唯一不同的里面我们添加了一对<slot></slot>标签,这就是插槽标签。这对标签就好比我们在 child 组件内部挖了一个槽出来,我们接下来就可以往这个槽里面放置一些内容。

那么我们如何往这个槽里面放置内容呢?

我们在 App.vue 里面通过一对闭合标签<child></child>调用了子组件,我们都知道 HTML 标签之间是可以插入内容的,虽然 child 不是 HTML 自带的标签,但是它却有着类似的特征,比如我们往<child></child>之间插入一点内容,代码如下:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child>
    <div>小猪课堂</div>
  </child>
</template>

输出结果:

我们发现在<child></child>标签之间插入的内容被渲染出来了,那么这是为何呢?

前面我们说 slot 就是挖了一个槽出来,可以放置东西,这里我们在父组件中添加的 div 便就是我们要添加的东西,子组件中 slot 标签被替换为了我们插入的 div 元素。这就是插槽的最基本使用。

结论:

为了更好理解插槽,简单总结为以下几点:

  • slot 是 Vue3 中的内置标签。
  • slot 相当于给子组件挖出了一个槽,可以用来填充内容。
  • 父组件中调用子组件时,子组件标签之间的内容元素就是要放置的内容,它会把 slot 标签替换掉。

最简单的理解: 我们的使用 U 盘需要将 U 盘插入 USB 口中,此时 USB 口就是插槽,U 盘就是插口。在 Vue 中,<slot></slot>就是电脑插槽,父组件的内容就可以理解为 U 盘插口。

3.插槽默认内容

我们通常将插槽比作一个占位符,有内容进来时,自动把 slot 给替换掉。但是,如果没有内容进来时,那么应该渲染什么呢?

在很多场景下都会有这种需求,比如 UI 组件库中的弹窗,如果我们没有传入弹窗的头部或者底部,那么弹窗便会有默认的样式效果,这里就用到了 slot 的默认内容功能。

修改一下 child.vue 代码:

<template>
  <div class="child-box">
    <p>我是子组件</p>
    <!-- 插槽 -->
    <slot>
      <p>我是默认内容</p>
    </slot>
  </div>
</template>

当我们的 App.vue 没有向 child 组件传入内容时,会是什么效果呢?

App.vue 代码如下:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child></child>
</template>

输出结果:

可以看到子组件同样渲染了内容,而且就是 slot 标签内的内容。那么我们我们往 child 组件传入一点内容会是什么效果呢?

App.vue 代码如下:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child>
    <div>{{ message }}</div>
  </child>
</template>


<script setup lang="ts">
import { ref } from "vue";
import Child from "./child.vue";
const message = ref("小猪课堂");
</script>

输出结果:

可以看到此时页面上渲染的 App.vue 父组件传入的内容了。

总结:

从上面例子不难看出,slot 标签内的内容就是默认内容,也就是当父组件没有传递给子组件内容时,子组件就会默认渲染 slot 内部的内容,但是 slot 标签是不会渲染出来的。

4.具名插槽

很多时候我们子组件中都不止只有一个 slot,比如弹窗组件,我们可能允许调用者同时传入 headercontentfooter 等等,这个时候如果子组件中只有一个 slot,那么这么多内容该如何区分,或者说该如何渲染呢?

4.1 基本使用

这个时候为了区分插槽与内容的对应关系,我们可以分别给 slot 和内容都加上一个名字,插入插槽的时候大家按照名字区分好就可以了。

我们给 child 组件添加上多个 slot,并且给每个 slot 取上一个名字。

代码如下:

<template>
  <div class="child-box">
    <p>我是子组件</p>
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot>
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

上段代码中我们添加了 3 个 slot 插槽,并且给其中两个 slot 标签添加了一个 name 属性,也就是每个插槽的名字。需要注意的是,上段代码中有一个插槽我们没有添加 name 属性,这个时候 Vue 会隐式的将这个插槽命名为“default”,接下来就是我们父组件 App.vue 添加内容了。

代码如下:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child>
    <template v-slot:header>
      <div>我是 header:{{ message }}</div>
    </template>
    <div>我没有名字:{{ message }}</div>
    <template v-slot:footer>
      <div>我是 footer:{{ message }}</div>
    </template>
  </child>
</template>

输出结果:

既然 slot 有了名字,那么我们在父组件中传入内容时就要和名字关系对应起来,我们采用 v-slot:header 指令的形式找到对应的插槽,需要注意的是该指令需要作用在 template 元素上。从上图可以看出,我们传入的内容都渲染到了对应的插槽内,没有命名的插槽渲染了我们传入的未添加指令的内容。

4.2 简写

在 Vue 中,很多指令都有简写形式,v-slot:name 指令也有简写形式,比如看我们下面的示例。

原写法:

<template v-slot:footer>
</template>

简写法:

<template #footer>
</template>

接下来我们在借用官网的一张图来清楚的了解具名插槽中的父子组件关系。

其中 BaseLayout 为一个子组件,就和我们 child 组件一样。

4.3 默认插槽与具名插槽混用

当一个子组件中既有具名插槽,又有默认插槽时,该如何渲染呢?

前面我们说默认插槽会被隐式的命名为 default,所以我们传入内容时可以将插槽名字改为 defalut 即可。

修改 child 组件:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child>
    <template v-slot:header>
      <div>我是 header:{{ message }}</div>
    </template>
    <template v-slot:default>
      <div>我没有名字:{{ message }}</div>
      <div>我没有名字:{{ message }}</div>
      <div>我没有名字:{{ message }}</div>
    </template>
    <template v-slot:footer>
      <div>我是 footer:{{ message }}</div>
    </template>
  </child>
</template>

虽然说子组件中有一个 slot 没有取名字,但是默认可以用 default 来代表它,就好比人刚出生的时候没有名字,但是他又一个默认属性:“人”。

当然,既然大家都是默认的,在父组件中你也可以不用名字,这个时候内容会默认传入到未命名插槽中去。

代码如下:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child>
    <template v-slot:header>
      <div>我是 header:{{ message }}</div>
    </template>
    <div>我没有名字:{{ message }}</div>
    <div>我没有名字:{{ message }}</div>
    <div>我没有名字:{{ message }}</div>
    <template v-slot:footer>
      <div>我是 footer:{{ message }}</div>
    </template>
  </child>
</template>

输出结果:

5.动态插槽名

前面我们给插槽命名的时候都是直接写死的,其实我们有时候可以动态给插槽命名的,以满足更多的业务场景。

代码如下:

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
  <!-- 缩写为 -->
  <template #[dynamicSlotName]>
    ...
  </template>
</base-layout>

上段代码就是在父组件中采用动态插槽名传入内容的示例。

6.插槽作用域问题

我们仔细思考插槽的使用,会发现这有一点类似于父子组件传递,只不过插槽传递的是模板内容罢了。那么涉及到传值,就会有一个作用域的问题,我们回顾一下 App.vue 中的一段代码。

代码如下:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child>
    <div>{{ message }}</div>
  </child>
</template>


<script setup lang="ts">
import { ref } from "vue";
import Child from "./child.vue";
const message = ref("小猪课堂");
</script>

上段代码中 message 是我们在父组件中定义的数据,但是在我们的子组件 child 中渲染了出来,说明子组件中的插槽是可以访问到父组件中的数据作用域的,但是反过来是不行的,因为我们无法通过插槽拿到子组件的数据。

总结:

所以我们这里总结为两点

  • 插槽内容可以访问到父组件的数据作用域,就好比上述中的 message 是父组件的。
  • 插槽内容无法访问到子组件的数据,就好比上述 App.vue 中的插槽内容拿不到子组件 child 的数据。

7.作用域插槽

前一节我们说父组件中的插槽内容是无法访问到子组件中的数据的,但是,万一我们有需求就是需要在插槽内容中获取子组件数据怎么办呢?

Vue3 给我们提供了方法,使用起来也比较简单。

7.1 默认插槽作用域传值

我们先来演示默认插槽如何获取子组件的数据。

child.vue 代码如下:

<template>
  <div class="child-box">
    <p>我是子组件</p>
    <slot text="我是子组件小猪课堂" :count="1"></slot>
  </div>
</template>

App.vue 组件代码:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child v-slot="slotProps">
    <div>{{ slotProps.text }}---{{ slotProps.count }}</div>
  </child>
</template>

输出结果:

上段代码中我们在子组件中 slot 标签上添加了一些自定义属性,属性值就是我们想要传递给父组件的一些内容。在父组件 App.vue 中通过 v-slot="slotProps"等形式接收子组件传毒过来的数据,slotProps 的名字是可以任意取的,它是一个对象,包含了所有传递过来的数据。

需要注意的是,子组件传递过来的数据只能在子组件这个标签内使用。

解构写法:

我们都知道对象是可以解构的,所以我们在父组件中还可以直接使用解构的写法来获取数据。

代码如下:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child v-slot="{ text, count }">
    <div>{{ text }}---{{ count }}</div>
  </child>
</template>

7.2 具名插槽作用域传值

具名插槽作用域之间的传递其实默认插槽作用域传值原理是一样的,只不过写法不一样罢了。

child.vue 代码如下:

<template>
  <div class="child-box">
    <p>我是子组件</p>
    <slot name="header" text="我是子组件小猪课堂" :count="1"></slot>
  </div>
</template>

App.vue 代码如下:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <child>
    <template #header="{ text, count }">
      <div>{{ text }}---{{ count }}</div>
    </template>
  </child>
</template>

上段代码中我们给 slot 添加了一个 name,在父组件中接收数据的时候不在采用 v-slot=""形式了,而是直接再插槽内容上采用#header=""形式,当时这是简写形式,你也可以写为:v-slot:header=""

总结

插槽的作用非常广泛,学好插槽对我们的项目开发有着非常大的帮助,当然,想要非常优雅的使用插槽,还是需要费一些功夫的。这里可以推荐大家去看一看element组件库中的table的使用,看看它是如何使用插槽的,如何优雅的将表格组件中的数据共享给父组件的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405391.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

axios无法加载响应数据:no data found for resource with given identifier

美好的、令人遐想的日落黄昏里&#xff0c;出现了诡异的bug&#xff01; 老师上课的时候&#xff0c;不好好听听&#xff0c;不仔细看&#xff01;那么花了那么多时间找bug问题~翻了好多方案&#xff0c;还未解决&#xff0c;然后遇到了我&#xff0c;这个大冤种就是你&#xf…

EasyExcel解析动态表头及导出

前言 excel文件导入及导出&#xff0c;是日常开发中经常遇到的需求。本次笔者以EasyExcel为例&#xff0c;针对在项目中遇到的动态表头解析及导出的场景&#xff0c;详细介绍具体的代码实现过程。 参考地址 https://github.com/alibaba/easyexcel 前端下载 const download …

JavaScript判断对象是否为空对象的几种方法

目录 1、空对象对应的字符串为 "{}" 2、for in 3、jquery 的 isEmptyObject()方法 4、Object.getOwnPropertyNames() 5、ES6 的 Object.keys() JSON.stringify()扩展 1、第一大特性 小结 2、第二大特性 3、第三大特性 4、第四大特性 5、第五大特性 6、第…

Vue实战——使用代理服务器解决跨域问题——No‘Access-Control-Allow-Origin‘ header is present on the requested resource

概论&#xff1a; 目录 一、跨域问题是怎么产生的 1.1 跨域问题&#xff1a; 1.2 解决办法 三、开启代理服务器 第一种方式&#xff1a;&#xff08;存在弊端&#xff09; 细节问题&#xff1a;&#xff08;解释两个弊端&#xff09; 第二种方式&#xff1a;&#xff08…

el-input设置必填提示(单个多个)

有两种:一种是多个el-input通过同一个el-form表单来限制,这种用得最多的地方就是添加和修改功能;另一种是每个el-input通过各自的el-form表单来限制,这种通常是用在动态添加多个输入框等功能上&#xff0c;话不多说&#xff0c;上才艺噻. 第一种&#xff08;多个el-input同时限…

【JavaScript】JS实用案例分享:DOM节点转JSON数据 | 标签输入框

&#x1f5a5;️ NodeJS专栏&#xff1a;Node.js从入门到精通 &#x1f5a5;️ 博主的前端之路&#xff08;源创征文一等奖作品&#xff09;&#xff1a;前端之行&#xff0c;任重道远&#xff08;来自大三学长的万字自述&#xff09; &#x1f5a5;️ TypeScript知识总结&…

微信小程序--》tabBar底部栏

&#x1f3cd;️作者简介&#xff1a;大家好&#xff0c;我是亦世凡华、渴望知识储备自己的一名在校大学生 &#x1f6f5;个人主页&#xff1a;亦世凡华、 &#x1f6fa;系列专栏&#xff1a;微信小程序 &#x1f6b2;座右铭&#xff1a;人生亦可燃烧&#xff0c;亦可腐败&…

搭建博客,基于vue3 的 vitepress 轻松搞定

Ⅰ、什么是vitepress &#x1f48e; vitepress 使用场景 简单的说 &#xff0c;只要 会用 markdown 语法&#xff0c;就能构建自己的 「博客、笔记、使用文档」等系统 &#xff1b; ✨ vitepress 优势 优势介绍傻瓜式操作只需要配置 菜单 和 对应的 markdown 就能实现博客、笔…

【Vue脚手架安装教程】

文章目录前言一、安装Node.js二、配置淘宝镜像安装cnpm,将npm设置为淘宝镜像&#xff1a;二、安装vue/cli检查是否安装成功&#xff1a; vue -V 或者 vue --version ![在这里插入图片描述](https://img-blog.csdnimg.cn/7f66366eba81456388fcf28871db0650.png)三、 创建一个vue…

Chrome浏览器的跨域设置

做前后端分离的开发的时候&#xff0c;出于一些原因往往需要将浏览器设置成支持跨域的模式&#xff0c;而且chrome浏览器支持可跨域的设置&#xff0c;但是新版本的chrome浏览器提高了跨域设置的门槛&#xff0c;原来的方法不再适用了。其实网上也有很多大神总结的chrome跨域设…

webpack的面试题(吐血整理)

以下为整理的webpack面试题&#xff0c;如有不足之处&#xff0c;还请大家多多指正。 一、webpack的构建流程 二、对webpack的理解 webpack是一个打包模块化js的工具&#xff0c;在webpack里一切文件皆模块&#xff0c;通过loader转换文件&#xff0c;通过plugin注入钩子&#…

最常见的六种跨域解决方案

目录&#xff1a; 前言&#xff1a;什么是跨域&#xff1f;JSONPCORS搭建Node代理服务器Nginx反向代理postMessageWebsocket总结 前言&#xff1a;什么是跨域&#xff1f; 跨域就是当在页面上发送ajax请求时&#xff0c;由于浏览器同源策略的限制&#xff0c;要求当前页面和…

jQuery模态弹窗插件(jquery-confirm)

前言 今天为大家分享一款开源的非常轻量且精美的jQuery模态弹窗插件&#xff1a;jquery-confirm&#xff0c;它包含Bootstrap,Material等多种主题供选择。 如果你的前端项目中还在使用jQuery&#xff0c;那么jquery-confirm是你模态弹窗的完美选择。 下面我们就来零距离感受…

IDEA如何运行SpringBoot项目(超详细截图)

【辰兮要努力】&#xff1a;hello你好我是辰兮&#xff0c;很高兴你能来阅读&#xff0c;昵称是希望自己能不断精进&#xff0c;向着优秀程序员前行&#xff01; 博客来源于项目以及编程中遇到的问题总结&#xff0c;偶尔会有读书分享&#xff0c;我会陆续更新Java前端、后台、…

vue中组件的props属性(详)

今天这篇文章&#xff0c;让你彻底学会props属性…… props主要用于组件的传值&#xff0c;他的工作就是为了接收外面传过来的数据&#xff0c;与data、el、ref是一个级别的配置项。 问题一&#xff1a;那props具体是怎么使用呢&#xff1f;原理又是什么呢&#xff1f;往下看…

css绘制3D炫动ikun

今天做一个3D版的ikun。 先准备图片一张 代码浅析 页面整体div.contrainer,舞台div.stage,控制盒子div.control,图片盒子div.imgWrap,js载入div.img列表。 <div class"contrainer"><div class"stage"><div class"control">…

vue项目引入svg图标(完整步骤)

1. 安装svg依赖 在vue中首先需要安装可以加载svg的依赖。 npm安装&#xff1a;npm install svg-sprite-loader --save-dev 2. 创建svg文件夹存放svg图标 创建icons文件夹&#xff0c;在icons文件夹下创建svg文件夹存放本地svg图标。 3. vue.config.js 中配置svg图片 vue.c…

vue中使用echarts实现动态数据绑定、获取后端接口数据

之前几篇echarts的文章是实现了静态的柱状图、折线图、饼状图、地图&#xff0c;在项目中我们肯定是需要获取后端接口&#xff0c;将后端返回的数据显示在图表上&#xff0c;所以这次就记录一下如何实现echarts的动态数据绑定。 简单来讲&#xff0c;就是从接口获取到的数据&a…

Vue生命周期总结(四个阶段,八个钩子函数)

生命周期就是组件或者实例&#xff0c;从创建到被销毁&#xff08;初始化化数据、编译模板、挂载DOM、渲染一更新一渲染、卸载&#xff09;的一系列过程&#xff0c;我们称这是Vue的生命周期 文章目录一、Vue的生命周期阶段二、生命周期钩子函数1. beforeCreate2. created3. be…

ES6+--》熟知JS中的async函数

目录 async函数 await 表达式 async使用形式 async读取文件 async发送AJAX请求 与生成器(Generator)相比 async函数 async函数的返回值为 promise 对象&#xff0c;promise对象的结果由async函数执行的返回值决定。async函数能使得异步操作变得更加方便&#xff0c;简而…