【vue】14.插槽:构建可复用组件的关键

今天看代码的时候碰到了插槽,有些看不懂,所以写下这篇文章,系统地梳理一下关于插槽的内容,也希望给大家带来一些帮助。

// 我碰到的插槽长这样
<template  #default="scope">... 
</template>


一.什么是插槽?

根据 Vue 官方的定义:“插槽用于向子组件传递内容。和 prop 用于传递数据不同,插槽用于传递更丰富的内容,包括 HTML 元素和其他 Vue 组件。”

简单来说,插槽就像是组件预留的“空位”,允许向组件内部插入任何内容,无论是文本、HTML 元素还是其他组件。有了插槽组件更加灵活,可以根据不同的使用场景展示不同的内容。

听起来有点抽象,没关系,举个例子一下就懂了。

现在有一个界面,它是由许多个卡片组件构成的。我们称界面为父组件,卡片组件为子组件,如图:

先看看子组件和父组件的代码:

// 卡片组件  子组件
<template><div class="card"><slot name="header"></slot><slot name="image"></slot></div>
</template>
// 在父组件中使用子组件
<CardComponent><template #header><h2>vue</h2></template><template #image><img src="vue.jpg" alt="vue"></template></template>
</CardComponent><CardComponent><template #header><h2>react</h2></template><template #image><img src="react.jpg" alt="react"></template></template>
</CardComponent>// 后两个类似,省略

卡片组件包含标题和图片两部分,但其具体内容是由使用该组件的父组件决定的。那么,父组件如何知道内容应该传递到何处,以及如何进行传递呢?

传递到何处:

子组件通过定义带有特定名称的插槽来预留内容位置。例如,一个用于标题的插槽可以如下表示:

<slot name="header"></slot>

name="header" 属性定义了一个名为 header 的插槽。

如何传递:

父组件需要将要传递的内容包裹在 <template> 标签内,并通过 # 符号后跟插槽名称来指定内容的插入位置。例如,要将标题传递到名为 header 的插槽,可以这样做:

<template #header><h2>这是卡片标题</h2>
</template>

这样,父组件就能精确地将内容传递到子组件中预定的插槽位置。


二.插槽的种类及其具体使用

理解了插槽是什么后,我们来看看不同类型的插槽。Vue 3 主要有三种插槽:具名插槽、条件插槽、作用域插槽。

1.默认插槽

默认插槽也叫匿名插槽,是最简单的插槽形式。不需要为 <slot> 标签提供 name 属性,并且在使用组件时,也不需要在 <template> 上指定插槽名称。如果一个组件只包含一个插槽,那我们就可以使用默认插槽。

毕竟只有一个坑,不管你给不给这个坑起名字,传进去的萝卜都只能待这个坑。所以没必要给坑起名字,也没必要给要传进去的萝卜指定坑位,一个萝卜一个坑,直接传就行了。

如上图所示,你可以为插槽指定默认内容,就像这样:

<!-- child.vue -->
<template><div><slot>默认萝卜</slot></div>
</template>

现在,当在父组件中使用 <child> 且没有提供任何插槽内容时,就会渲染“默认萝卜”。

但是,如果父组件提供了插槽内容,那么子组件的默认内容就会被替换掉。

// 在父组件中使用子组件
<child>我是父组件传递的萝卜,我会取代之前的默认萝卜</child>

父萝卜驾到,通通闪开!


2.具名插槽

具名插槽,顾名思义,具有名字的插槽,也就是带“name”属性的插槽。

<slot> 元素可以有一个特殊的属性name,用来给各个插槽分配唯一的 ID,以确定每一处要渲染的内容。

如果我们需要给一个组件的多处地方填充内容,那么具名插槽就有用了。本文刚开始引入的卡片例子,就使用了具名插槽。

本质上是多个萝卜多个坑的问题。要怎么实现把萝卜放进对应的坑里?首先给坑位起名字,然后告诉萝卜,你要去哪个坑,就好了。

再举一个例子:

// 在父组件中使用子组件
<child><template #header><h1>我是标题</h1></template><template #default><p>我是第一段话</p><p>我是第二段话</p></template><template #footer><p>我是底部信息</p></template>
</child>
// 子组件
<div><header><slot name="header"></slot></header><main><slot></slot></main><footer><slot name="footer"></slot></footer></div>

上面带name属性的就是具名插槽,如果不带name,那么那么它的name默认为default。当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非 <template> 节点都被隐式地视为默认插槽的内容。

所以上面的父组件也可以写成:

// 在父组件中使用子组件
<child><template #header><h1>我是标题</h1></template><p>我是第一段话</p><p>我是第二段话</p><template #footer><p>我是底部信息</p></template>
</child>

如果你要把多个萝卜放入多个坑里,知道自己要去哪个坑的萝卜就会自己找到对应name的坑进去,其他的萝卜都进入默认的坑。


3.作用域插槽

(1)渲染作用域

在了解作用域插槽之前,有必要了解一下“渲染作用域”。

vue官网对“渲染作用域”的描述:

插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的。举例来说:

<span>{{ message }}</span>
<FancyButton>{{ message }}</FancyButton>

这里的两个 {{ message }} 插值表达式渲染的内容都是一样的。

插槽内容无法访问子组件的数据。Vue 模板中的表达式只能访问其定义时所处的作用域,这和 JavaScript 的词法作用域规则是一致的。换言之:

父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。

在 Vue 中,组件的作用域规则是这样的:

  • 父组件模板中的所有内容都是在父组件的作用域中编译的。在父组件模板中,可以访问父组件的数据和方法。
  • 子组件模板中的所有内容都是在子组件的作用域中编译的。在子组件模板中,可以访问子组件的数据和方法。

插槽内容也是如此:

  • 当在父组件中使用子组件并定义插槽内容时,这些插槽内容是在父组件的作用域中编译的。因此,可以在插槽内容中使用父组件的数据和方法,但不能直接使用子组件的数据和方法。
  • 子组件可以通过 props 接收来自父组件的数据,但是插槽内容本身不能直接访问子组件的数据。

那如果我们需要在插槽内容中使用子组件的数据呢?

那就要用到“作用域插槽”了。

(2)默认作用域插槽

在子组件slot标签绑定属性,然后在父组件中用v-slot进行接收,就可以把数据传递给父组件中。

在接收方式上,默认插槽和具名插槽有一些不同,先来看看默认插槽如何接收子组件传过来的props:

//子组件
<template><div><slot personName="清清" age="3"></slot></div>
</template>//父组件<template><div><Child v-slot="slotProps">我是 {{ slotProps.personName }} ,我今年 {{ slotProps.age }} 岁了。</Child></div>
</template>
<script setup>
import Child from './Child.vue'
</script>

这里的slotProps是插槽 prop 的名字,可以自定义,方便后面使用。

也可以接收响应式数据:

(3)具名作用域插槽

具名作用域插槽允许给插槽起个名字,并且可以通过 v-slot:插槽名字="slotProps" 的方式来接收子组件传递的数据。如果用缩写的话,可以写成 #插槽名字="slotProps"

<MyComponent><template #header="headerProps">{{ headerProps }}</template><template #default="defaultProps">{{ defaultProps }}</template><template #footer="footerProps">{{ footerProps }}</template>
</MyComponent>

子组件传递数据给插槽::

<slot name="header" message="hello"></slot>

插槽的 name 是 Vue 保留的属性,不会作为数据传递给插槽。所以,父组件拿到的headerProps,它只会包含 { message: 'hello' }

(4)注意事项

如果同时使用了具名插槽和默认插槽,那么需要为默认插槽明确地使用 <template> 标签。如果不这样做,可能会出现编译错误,因为这样容易混淆哪个数据属于哪个插槽。

举个例子,有一个组件 MyComponent,它有一个默认插槽和一个名为 footer 的具名插槽,我们不能直接在组件上使用 v-slot 指令,这样会导致数据的作用域不清楚。

所以,我们应该这样做:

<MyComponent><!-- 明确地使用默认插槽 --><template #default="{ message }"><p>{{ message }}</p></template><!-- 具名插槽 --><template #footer><p>这里有一些联系信息</p></template>
</MyComponent>

这样的话, message 只在默认插槽中可用,而在 footer 插槽中不可用。这样代码更清晰,也更不容易出错。

通过上述例子,我们可以看到插槽在 Vue 3 中的强大之处。它们不仅使组件更加灵活,还极大地提高了组件的可复用性。

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

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

相关文章

camera和lidar外参标定

雷达和相机的外参标定&#xff08;外部参数标定&#xff09;指的是确定两者之间的旋转和平移关系&#xff0c;使得它们的坐标系可以对齐。 文章目录 无目标标定livox_camera_calibdirect_visual_lidar_calibration 有目标标定velo2cam_calibration 无目标标定 livox_camera_ca…

数据结构和算法-动态规划(3)-经典问题

动态规划常见问题 打家劫舍 题目 [力扣198] 198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 题目描述 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&…

深入理解Redis的四种模式

Redis是一个内存数据存储系统&#xff0c;支持多种不同的部署模式。以下是Redis的四种主要部署模式。 1、单机模式 单机模式是最简单的部署模式&#xff0c;Redis将数据存储在单个节点上。这个节点包括一个Redis进程和一个持久化存储。单机模式非常适合小型应用程序或者开发和…

Flutter实战短视频课程

1、课程导学 一套代研运行多蜡 体州一致&#xff0c;目胜能优昇 未来大趋势 不改交原生项目的基础上&#xff0c;扩展Flutter能力 Flutter原生灵话切涣 0入侵 最简单、最通用 最新Flutter 3,x新特性讲解 大量flutter官方组件和api学习 最常用的第三方库使用及原理解析 自研组…

消息队列-Rabbitmq(消息发送,消息接收)

将来我们开发业务功能的时候&#xff0c;肯定不会在控制台收发消息&#xff0c;而是应该基于编程的方式。由于RabbitMQ采用了AMQP协议&#xff0c;因此它具备跨语言的特性。任何语言只要遵循AMQP协议收发消息&#xff0c;都可以与RabbitMQ交互。并且RabbitMQ官方也提供了各种不…

QT相机连接与拍照

先看效果 编辑:已添加虚拟键盘辅助输入,添加二维码识别,用的QZxing 初始化 auto mainLayout = new QHBoxLayout(this);m_viewfinder = new QCameraViewfinder(this);m_viewfinder->setStyleSheet("border-radius: 20px;background-color:rgb(43,48,70)");mainL…

ubuntu openmpi安装(超简单)

openmpi安装 apt update apt install openmpi-bin openmpi-common libopenmpi-dev安装到此完毕 测试一下&#xff0c;success !

【C++】string 类深度解析:探秘字符串操作的核心

快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 目录 &#x1f4af;前言 &#x1f4af;为什么要学习 string 类 &#xff08;一&#xff09;简化操作 &#xff08;二&#xff09;确保安全 &#xff08;三…

【EndNote版】如何在Word中引用文献

1、在Word中&#xff0c;鼠标光标放在所需插入文献的位置 2、点击选项卡中的“EndNote X9”&#xff0c;直接在EndNote中选中对应的文献 3、选中文献&#xff0c;点击工具栏中的“引用” 4、最后就可在Word中看到所插入的文献

[面试题]ES6 Javascript

ES6 箭头函数和普通函数有什么区别? 1)定义方式:箭头函数使用箭头(>)语法&#xff0c;省略了 function 关键字。 2)参数处理:如果只有一个参数&#xff0c;箭头函数可以省略括号。 3)函数体:如果函数体只有一条语句&#xff0c;箭头函数可以省略花括号和 return 关键字 4)…

Leetcode 二叉树中的最大路径和

算法思想 这道题要求在一棵二叉树中找到路径和最大的路径。路径可以从树中任意一个节点开始&#xff0c;到任意一个节点结束&#xff0c;但路径上的节点必须是连续的。 算法使用递归的方式来遍历树中的每个节点&#xff0c;并在遍历过程中计算包含当前节点的最大路径和。具体…

计算机视觉实验一:图像基础处理

1. 图像的直方图均衡 1.1 实验目的与要求 (1)理解直方图均衡的原理与作用; (2)掌握统计图像直方图的方法; (3)掌握图像直方图均衡的方法。 1.2 实验原理及知识点 直方图均衡化是通过灰度变换将一幅图象转换为另一幅均衡直方图&#xff0c;即在每个灰度级上都具有相同的象素…

计算结构力学:多自由度振动系统

本文以笔记的形式记录计算结构力学的若干基础知识。 注1&#xff1a;限于研究水平&#xff0c;分析难免不当&#xff0c;欢迎批评指正。 注2&#xff1a;文章内容会不定期更新。 预修1&#xff1a;线性代数 1. 标准特征值 复矩阵Schur分解&#xff1a;对于复矩阵&#xff0c…

Linux基础环境搭建(CentOS7)- 安装Scala和Spark

#Linux基础环境搭建&#xff08;CentOS7&#xff09;- 安装Scala和Spark Linux基础环境搭建&#xff08;CentOS7&#xff09;- 安装Scala和Spark 大家注意以下的环境搭建版本号&#xff0c;如果版本不匹配有可能出现问题&#xff01;&#xff08;spark不要下2.4版本的 会报错…

Vue3使用AntV | X6绘制流程图:开箱即用

x6官方地址X6图编辑引擎 | AntV 官方文档仔细地介绍了很多丰富的功能,这里的demo可以满足基本的使用,具体拓展还需要仔细看文档内容 先上效果图 1、安装 通过 npm 或 yarn 命令安装 X6。 # npm npm install @antv/x6 --save# yarn yarn add @antv/x6 初始化画布 <di…

安装使用docker harbor并推送镜像到仓库

1.概要 通过上一章节的讲解&#xff0c;我们基本了解了docker的操作命令&#xff0c;在文章的最后我们成功的推送一个镜像到DockerHub的镜像仓库。从流程上说&#xff0c;操作过程可以说很完美&#xff0c;但是整个推送过程消耗的时间太长&#xff0c;我们消耗了大量时间在访问…

HTML练习题:彼岸的花(web)

展示效果: 代码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>彼岸の花</title><style…

thinkphp和vue基于Workerman搭建Websocket服务实现用户实时聊天,完整前后端源码demo及数据表sql

最近接了一个陪玩小程序&#xff0c;其中有一个实时聊天的项目&#xff0c;需要搭建Websocke服务&#xff0c;通过多方考虑选择了通过GatewayWorker框架&#xff08;基于Workerman&#xff09;,将代码提取了出来&#xff0c;用到的框架封装到了vendor目录下&#xff0c;完整前后…

【计算机网络 - 基础问题】每日 3 题(五十八)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

C++ 二叉树进阶:相关习题解析

目录 1. 二叉树创建字符串。 2. 二叉树的分层遍历1 3. 二叉树的分层遍历2 4. 二叉树的最近公共祖先 5. 将二叉搜索树转换为排序的双向链表 6. 从前序与中序遍历序列构造二叉树 7. 从中序与后序遍历序列构造二叉树 8. 二叉树的前序遍历&#xff0c;非递归迭代实现 9.…