当前位置: 首页 > news >正文

深入理解Vue slot的原理

文章目录

  • 前言
  • 为什么需要插槽
  • 作用域插槽
  • 插槽的原理
  • 总结

前言

插槽是Vue中一个重要的特性,它有很多种用法:默认插槽、具名插槽、作用域插槽。尤其作用域插槽,还有一堆特性,比如解构prop,解构prop的时候还可以进行属性名的映射。
记不住,根本记不住。
死记硬背当然记不住,但只要了解了原理,这些根本不用记。

为什么需要插槽

在深入原理之前,我们还是巩固一下基础。
为什么我们需要插槽这个特性,插槽到底是什么?
如果你看的是Vue2的文档,那么你会一头雾水:
在这里插入图片描述
Vue2几乎是没什么铺垫,上来就给你介绍插槽的特性。所以插槽到底是什么,为什么要用这个东西,得你自己悟。
Vue3的文档稍微好一点:
在这里插入图片描述
Vue3的文档说到了插槽的一些关键的点,但仍然很隐晦。
这里我们戳破这层窗户纸,给插槽一个明确的定义:

  1. 插槽给是组件的一种传参方式。组件可以通过props传参,也可以通过插槽传参。
  2. props传参传的是对象或值,插槽传的是模板内容
  3. 使用插槽的目的是将一部分由子组件负责的渲染工作交给父组件定义,提高的组件的灵活性

为什么要使用插槽呢?接下来我通过一个例子来说明。
现在假设你要实现一个无序列表的组件,基本长下面这样:
在这里插入图片描述
但是用户可能不满足于此,他们希望能让选项的字体加粗,或者变成斜体,或者改变字体颜色,或者在选项前面增加图标。更有甚者,他们希望选项的内容可以是更加复杂的DOM结构。

怎么办?如果没有插槽,你只能给组件提供足够多的props,让用户通过设置这些props来定制自己想要的效果。用户有新的需求,你也要跟着修改。

用插槽就可以完美解决这个问题。
我们定义一个组件List:

<script setup>let props = defineProps(['data'])
</script><template><ul><li v-for="item in props.data"><slot v-bind="item">{{item.text}}</slot></li></ul>
</template>

父组件可以这么用:

<script setup>
import { ref } from 'vue'
import List from './List.vue';const data = [ {text: 'Java' }, { text: 'PHP'}, { text: 'CSS'} ]
</script><template><List :data />
</template>

这里使用的是后备内容,所以就是平平无奇的展示。
在这里插入图片描述

如果父组件想要让文字加粗或者使用斜体或改变颜色,它可以自己定义:

<template v-slot="data"><b><i>{{data.text}}</i></b></template>

List组件不需要做任何改动。

作用域插槽

这里我们不在赘述默认插槽、具名插槽,这没啥好说的,我们直接来看作用域插槽。
作用域插槽的难点就在解构prop上,写法有很多种,比如:

<template v-slot="{ user }">{{ user.name }}
</template>

你有没有想过为啥user要包裹一个花括号,你也可以不包裹:

<template v-slot="scope">{{ scope.user.name }}
</template>

你还可以进行属性映射:

<template v-slot="{ user: person }">{{ person.name }}
</template>

你还可以这样:

<template v-slot="{ user = { name: 'Guest' } }">{{ user.name }}
</template>

不是,这都是啥,直接懵了呀。

  • 我为什么要加括号,什么时候不加
  • 属性映射是个啥,有啥用呀
  • 解构的时候还可以提供默认值?
  • 还有这是Vue的模板语法,还是JS的语法呀

有这些疑问都是因为不熟悉插槽的原理。不熟悉原理就只能死记硬背,熟悉了,根本就不用记。
在vue2的文档里面有对解构的原理进行解释:
在这里插入图片描述
所以这些语法不是Vue创造的,而是ES2015的函数参数解构的语法,比如:
普通的参数解构

function test({ name }) {console.log(name)
}let user = { name: '张三', age: 18 }
test(user) // 张三

解构的时候提供默认值:

function test({ name='张三' }) {console.log(name)
}let user = { age: 18 }
test(user) // 张三
user.name = '李四'
test(user) // 李四

解构的时候进行属性映射:

function test({ name: userName}) {console.log(userName)
}let user = { name: '张三', age: 18 }
test(user) // 张三

只要这种参数解构的语法是JS支持的,那么Vue的插槽就是支持的,你还需要死记硬背吗。

插槽的原理

最后我们终于要系统性的看看插槽是怎么实现的了,我们可以在Vue的Playground看看插槽编译后的结果。
子组件编译后的关键代码:
在这里插入图片描述
子组件的render函数中通过调用renderSlot方法来渲染插槽,你可以认为子组件会去调用:

_ctx.$slots.default({item})

如果父组件没有提供插槽的模板,子组件就会渲染后备内容,也就是:

_createTextVNode(_toDisplayString(item.text), 1 /* TEXT */)

接下来我们再看看父组件编译后的关键代码:
在这里插入图片描述
父组件通过createBlock渲染子组件,第三个参数传的是插槽的实现,default就是默认插槽的名字(如果是具名插槽,那么就是对应插槽的名字)。
我通过JS的高阶函数来模拟这个过程,让大家更容易理解这个原理。
现在假设我一个函数list:

function list(consumer) {const data = [ {text: 'Java' }, { text: 'PHP'}, { text: 'CSS'} ]for (let item of data) {consumer(item)}
}

list函数可以通过接收一个consumer,让调用方来控制输出的方式。
调用方,可以这样:

list((data) => console.log(data.text))
// Java
// PHP
// CSS

也可以控制输出,比如:

list((data) => console.log('==', data.text, '=='))
// ==Java==
// ==PHP==
// ==CSS==

也可以解构:

list(({text}) => console.log(text))
// Java
// PHP
// CSS

这样是不是更容易理解了。
父组件不同的插槽实现,编译出来的结果也不一样,这就是vue的编译器要做的事情了。
比如,我们看看prop解构的时候,编译的结果是什么样子的。
没有解构的情况:

<template v-slot="data">{{data.text}}</template>

编译后:
在这里插入图片描述
有解构:

<template v-slot="{text}">{{text}}</template>

编译后:
在这里插入图片描述
解构的时候进行属性映射:

<template v-slot="{text: name}">{{name}}</template>

编译后:
在这里插入图片描述
提供参数默认值:
在这里插入图片描述
是不是一模一样!所以这块就是用的JS的语法特性。

什么时候需要进行解构,什么时候不需要呢,这取决于父组件需要关注哪些prop。
子组件定义插槽的时候,可以绑定多个属性,比如:

<slot :text="item.text" :icon="item.icon">{{item.text}}</slot>

编译后的结果如下:
在这里插入图片描述
如果父组件提供插槽内容的时候只使用text,那么就可以只解构出text属性。

<template v-slot="{ text }">{{text}}</template>

如果text和icon都要用到,那么就都解构:

<template v-slot="{ text, icon }"><i class="fa" :class="'fa-' + icon"></i><span>{{text}}</span></template>

或者不解构:

<template v-slot="item"><i class="fa" :class="'fa-' + item.icon"></i><span>{{item.text}}</span></template>

这些都不需要死记硬背,你知道了原理,知道了父组件v-slot的内容就是子组件所有bind的属性组成的对象,知道了它的结构,你就知道要不要解构,以及可以怎么解构。

总结

总结一下,最重要的三个结论:

  1. 插槽是一种组件的传参方式,可以传递模板内容,可以提高组件的灵活性
  2. 插槽的本质就是JS的高阶函数,函数由父组件实现,子组件调用
  3. 插槽的prop解构不是vue的语法,本质就是ES6方法参数的解构语法

相关文章:

深入理解Vue slot的原理

文章目录 前言为什么需要插槽作用域插槽插槽的原理总结 前言 插槽是Vue中一个重要的特性&#xff0c;它有很多种用法&#xff1a;默认插槽、具名插槽、作用域插槽。尤其作用域插槽&#xff0c;还有一堆特性&#xff0c;比如解构prop&#xff0c;解构prop的时候还可以进行属性名…...

git fetch作用与用法

目录 git fetch作用 git fetch用法 git fetch作用 git fetch 命令在 Git 版本控制系统中扮演着重要的角色。其主要作用是从远程仓库获取最新版本的项目文件&#xff0c;但不会自动合并或修改你当前的工作。这意味着&#xff0c;使用 git fetch 后&#xff0c;你需要手动合并…...

pycharm如何查看git历史版本变更信息

通过名字查看不同版本 查看版本不同地方...

【2.2 python中的变量】

2.2 python中的变量 在Python中&#xff0c;变量是存储数据值的容器。Python是一种动态类型语言&#xff0c;这意味着你不需要在声明变量时指定变量的类型&#xff1b;Python会根据你赋给变量的值自动确定其类型。下面我将详细介绍Python中的变量&#xff0c;包括保留字&#…...

Python软体中找出一组字符串的最长公共前缀:算法与实现

Python软体中找出一组字符串的最长公共前缀:算法与实现 在处理字符串数据时,寻找多个字符串之间的共同特征是一个常见的需求。特别是在文件名、URL、或其他文本数据中,找到最长公共前缀(Longest Common Prefix, LCP)可以帮助我们进行更高效的搜索和分类。本文将详细介绍如…...

git lfs使用(huggingface下载大模型文件)-教程记录

写的比较清楚的教程&#xff0c;用于之后有需求时查找用&#xff1a; https://blog.csdn.net/flyingluohaipeng/article/details/130788293...

1. 什么是操作系统

文章目录 1.1 从功能上来看操作系统1.2 硬件资源 1.1 从功能上来看操作系统 对用户来说&#xff0c;操作系统是一个控制软件&#xff0c;可以用来管理应用程序&#xff0c;它可以限制不同的程序来占用的资源。对内部的软件来说&#xff0c;操作系统是一个管理外设和分配资源的…...

数据科学 - 数据预处理 (数据清洗,结构化数据)

1. 前言 数据清洗与结构化数据在数据分析和机器学习项目中扮演着至关重要的角色。随着大数据时代的到来&#xff0c;数据的质量、准确性和可用性成为决定项目成功与否的关键因素。 数据清洗提高数据质量&#xff0c;保证数据集的一致性&#xff1b;促进数据分析与挖掘&#xf…...

基于SpringBoot+Vue的校车调度管理系统(带1w+文档)

基于SpringBootVue的校车调度管理系统(带1w文档) 基于SpringBootVue的校车调度管理系统(带1w文档) 如今&#xff0c;因为无线网相关技术的快速&#xff0c;尤其是在网上进行资源的上传下载、搜索查询等技术&#xff0c;以及信息处理和语言开发技术的进步&#xff0c;同时编程语…...

基于改进拥挤距离的多模态多目标优化差分进化(MMODE-ICD)求解无人机三维路径规划(MATLAB代码)

一、无人机多目标优化模型 无人机三维路径规划是无人机在执行任务过程中的非常关键的环节&#xff0c;无人机三维路径规划的主要目的是在满足任务需求和自主飞行约束的基础上&#xff0c;计算出发点和目标点之间的最佳航路。 1.1路径成本 无人机三维路径规划的首要目标是寻找…...

opencascade AIS_Trihedron源码学习 绘制三轴坐标系

opencascade AIS_Trihedron 前言 //! 创建一个可选择的三轴坐标系 //! 该三轴坐标系包括一个原点&#xff0c;三个轴线和三个标签。 //! 标签的默认文本为 “X”, “Y”, “Z”。 //! 可以更改原点和任意轴线的颜色&#xff0c;箭头和标签的颜色也可以改变。 //! 可视化呈现可…...

【C++】C++应用案例-通讯录管理系统

目录 一、整体介绍 1.1、需求和目标 1.2、整体功能描述 二、页面及功能描述 2.1 主菜单 2.2 添加联系人菜单 2.3 显示联系人菜单 2.4 修改联系人菜单 2.5 退出功能 三、流程设计 3.1 主流程 3.2 添加操作流程 3.3 显示联系人操作流程 3.4 修改联系人操作流程 四…...

使用Python自动批量提取增值税发票信息并导出为Excel文件

要批量提取增值税发票的关键信息并将其导出为 Excel 文件&#xff0c;可以使用 Python 脚本结合 pdfplumber&#xff08;用于解析 PDF 内容&#xff09;、pandas&#xff08;用于处理数据并导出 Excel&#xff09;等库来实现。以下是实现这一目标的详细步骤。 1. 环境设置 首…...

vitis (eclipse) 的Indexer不能搜索、不能跳转到函数和变量定义和声明不能打开调用层次的解决方法

在使用vitis(2021.1) 过程中&#xff0c;有一个非常方便实用的功能&#xff0c;就是在函数或变量等源代码上通过右键菜单或快捷键F3、F4、CtrlAltH&#xff0c;也可以按住Ctrl键然后鼠标停留在函数名或变量名上&#xff0c;点击出现的链接&#xff0c;可以跳转到函数或变量的定…...

最佳HR软件指南:11款高效管理工具

文章介绍了11款人力资源管理工具&#xff1a;Moka、友人才、北森HRSaaS、同鑫eHR、i人事、红海eHR、BambooHR、Skuad、Hibob、OrangeHRM、Verint。 在选择人力资源管理软件时&#xff0c;选错不仅浪费时间和金钱&#xff0c;还会影响团队的工作效率和员工满意度。本文总结了11款…...

家长为孩子出国留学择校的四个步骤

如何为孩子选择最好的学校&#xff1f;无论您是选择公立或私立学校还是在家上学&#xff0c;无论您是否支付学费&#xff0c;都必须仔细规划。在为孩子选择学校的过程中&#xff0c;以下部分有供您考虑的问题。 写下对你来说最重要的五件事 在考虑选择学校时&#xff0c;您可…...

数据挖掘可以挖掘什么类型的模式?

一、挖掘频繁模式、关联和相关性 频繁模式&#xff08;frequent pettern&#xff09;是在数据中频繁出现的模式。 频繁项集一般是指频繁的在事务数据集中一起出现的商品的集合。 频繁出现的子序列&#xff0c;如顾客倾向于先买相机&#xff0c;再买内存卡这样的模式就是一个…...

JAVA中的隐式参数this

在Java中&#xff0c;this 关键字是一个非常重要的隐式参数&#xff0c;它代表当前对象的引用。通过 this&#xff0c;你可以访问类中的字段&#xff08;属性&#xff09;、方法以及构造函数中的参数&#xff08;当参数名与字段名相同时&#xff0c;用于区分&#xff09;。虽然…...

ThreadLocal 使用和详解避坑

在多线程编程中&#xff0c;每个线程都有自己的线程栈和线程本地存储。线程栈用于存储方法调用的信息&#xff0c;而线程本地存储则是每个线程私有的存储空间&#xff0c;用于存储线程的局部变量。ThreadLocal类提供了一种简单的方式来实现线程本地存储&#xff0c;它允许将线程…...

Python中使用类方法的返回值在其他方法中继续调用,return self进行链式调用

文章目录 return self进行链式调用继续思考&#xff0c;以下内容可以不看如果self中没有初始化valueself中定义其他变量&#xff0c;调用类方法外的函数 return self进行链式调用 在Python中&#xff0c;可以使用类方法的返回值在其他方法中继续调用。这通常通过返回类实例&am…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

用鸿蒙HarmonyOS5实现中国象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权

摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题&#xff1a;安全。文章将详细阐述认证&#xff08;Authentication) 与授权&#xff08;Authorization的核心概念&#xff0c;对比传统 Session-Cookie 与现代 JWT&#xff08;JS…...

土建施工员考试:建筑施工技术重点知识有哪些?

《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目&#xff0c;核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容&#xff0c;附学习方向和应试技巧&#xff1a; 一、施工组织与进度管理 核心目标&#xff1a; 规…...

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...