这应该是全网最详细的Vue3.5版本解读

news/2024/11/15 22:28:00/文章来源:https://www.cnblogs.com/heavenYJJ/p/18397413

前言

Vue3.5正式版在这两天发布了,网上已经有了不少关于Vue3.5版本的解读文章。但是欧阳发现这些文章对3.5中新增的功能介绍都不是很全,所以导致不少同学有个错觉,觉得Vue3.5版本不过如此,选择跳过这个版本等下个大版本再去更新。所以欧阳写了这篇超级详细的Vue3.5版本解读文章,小伙伴们可以看看在3.5版本中有没有增加一些你期待的功能。

关注公众号:【前端欧阳】,给自己一个进阶vue的机会

版本号

这次的版本号是天元突破红莲螺岩,这是07年出的一个二次元动漫,欧阳是没看过的。在此之前我一直以为这次的版本号会叫黑神话:悟空,可能悟空不够二次元吧。

响应式

响应式相关的内容主要分为:重构响应式、响应式props支持解构、新增onEffectCleanup函数、新增base watch函数、新增onWatcherCleanup函数、新增pauseresume方法。

重构响应式

这次响应式的重构是属于Vue内部优化,对于普通开发者来说是无感的。重构后内存占用减少了56%,优化手段主要是通过版本计数双向链表数据结构,灵感来源于Preact signals。后续欧阳会出一系列关于响应式相关的源码文章,大家可以关注一波欧阳。

响应式props支持解构

在3.5中响应式props支持解构终于正式稳定了,在没有这个功能之前我们想要在js中访问prop必须要这样写:props.name,否则name将会丢失响应式。

有了响应式props解构后,在js中我们就可以直接解构出name来使用,比如下面这样的代码:

<script setup lang="ts">
const { name } = defineProps({name: String,
});console.log(name);
</script>

defineProps搭配解构一起使用后,在编译时就可以将name处理成props.name。编译后简化的代码如下:

setup(__props) {console.log(__props.name);const __returned__ = {};return __returned__;
}

从上面的代码可以看到console.log(name)经过编译后变成了console.log(__props.name),这样处理后name当然就不会丢失响应式了。

新增onEffectCleanup函数

在组件卸载之前或者下一次watchEffect回调执行之前会自动调用onEffectCleanup函数,有了这个函数后你就不需要在组件的beforeUnmount钩子函数去统一清理一些timer了。比如下面这个场景:

import { watchEffect, ref } from "vue";
import { onEffectCleanup } from "@vue/reactivity";const flag = ref(true);
watchEffect(() => {if (flag.value) {const timer = setInterval(() => {// 做一些事情console.log("do something");}, 200);onEffectCleanup(() => {clearInterval(timer);});}
});

上面这个例子在watchEffect中会去注册一个循环调用的定时器,如果不使用onEffectCleanup,那么我们就需要在beforeUnmount钩子函数中去清理定时器。

但是有了onEffectCleanup后,将clearInterval放在他的回调中就可以了。当组件卸载时会自动执行onEffectCleanup传入的回调函数,也就是会执行clearInterval清除定时器。

还有一点值得注意的是onEffectCleanup函数目前没有在vue包中暴露出来,如果你想使用可以像我这样从@vue/reactivity包中导入onEffectCleanup函数。

新增base watch函数

我们之前使用的watch函数是和Vue组件以及生命周期一起实现的,他们是深度绑定的,所以watch函数代码的位置在vue源码中的runtime-core模块中。

但是有的场景中我们只想使用vue的响应式功能,也就是vue源码中的reactivity模块,比如小程序vuemini。为此我们不得不将runtime-core模块也导入到项目中,或者像vuemini一样去手写一个watch函数。

在3.5版本中重构了一个base watch函数,这个函数的实现和vue组件没有一毛钱关系,所以他是在reactivity模块中。详情可以查看我之前的文章: Vue3.5新增的baseWatch让watch函数和Vue组件彻底分手

还有一点就是这个base watch函数对于普通开发者来说没有什么影响,但是对于一些下游项目,比如vuemini来说是和受益的。

新增onWatcherCleanup函数

和前面的onEffectCleanup函数类似,在组件卸载之前或者下一次watch回调执行之前会自动调用onWatcherCleanup函数,同样有了这个函数后你就不需要在组件的beforeUnmount钩子函数去统一清理一些timer了。比如下面这个场景:

import { watch, ref, onWatcherCleanup } from "vue";watch(flag, () => {const timer = setInterval(() => {// 做一些事情console.log("do something");}, 200);onWatcherCleanup(() => {console.log("清理定时器");clearInterval(timer);});
});

onEffectCleanup函数不同的是我们可以从vue中import导入onWatcherCleanup函数。

新增pause和resume方法

有的场景中我们可能想在“一段时间中暂停一下”,不去执行watch或者watchEffect中的回调。等业务条件满足后再去恢复执行watch或者watchEffect中的回调。在这种场景中pauseresume方法就能派上用场啦。

下面这个是watchEffect的例子,代码如下:

<template><button @click="count++">count++</button><button @click="runner2.pause()">暂停</button><button @click="runner2.resume()">恢复</button>
</template><script setup lang="ts">
import { watchEffect } from "vue";const count = ref(0);
const runner = watchEffect(() => {if (count.value > 0) {console.log(count.value);}
});
</script>

在上面的demo中,点击count++按钮后理论上每次都会执行一次watchEffect的回调。

但是当我们点击了暂停按钮后就会执行pause方法进行暂停,在暂停期间watchEffect的回调就不会执行了。

当我们再次点击了恢复按钮后就会执行resume方法进行恢复,此时watchEffect的回调就会重新执行。

console.log的结果如下图:
console

从上图中可以看到count打印到4后就没接着打印了,因为我们执行了pause方法暂停了。当重新执行了resume方法恢复后可以看到count又重新开始打印了,此时从8开始打印了。

不光watchEffect可以执行pauseresume方法,watch一样也可以执行pauseresume方法。代码如下:

const runner = watch(count, () => {if (count.value > 0) {console.log(count.value);}
});runner.pause()	// 暂停方法
runner.resume()	// 恢复方法

watch的deep选项支持传入数字

在以前deep选项的值要么是false,要么是true,表明是否深度监听一个对象。在3.5中deep选项支持传入数字了,表明监控对象的深度。

比如下面的这个demo:

const obj1 = ref({a: {b: 1,c: {d: 2,e: {f: 3,},},},
});watch(obj1,() => {console.log("监听到obj1变化");},{deep: 3,}
);function changeDeep3Obj() {obj1.value.a.c.d = 20;
}function changeDeep4Obj() {obj1.value.a.c.e.f = 30;
}

在上面的例子watchdeep选项值是3,表明监听到对象的第3层。

changeDeep3Obj函数中就是修改对象的第3层的d属性,所以能够触发watch的回调。

changeDeep4Obj函数是修改对象的第4层的f属性,所以不能触发watch的回调。

SSR服务端渲染

服务端渲染SSR主要有这几个部分:新增useId函数、Lazy Hydration  懒加载水合、data-allow-mismatch

新增useId函数

有时我们需要生成一个随机数塞到DOM元素上,比如下面这个场景:

<template><label :htmlFor="id">Do you like Vue3.5?</label><input type="checkbox" name="vue3.5" :id="id" />
</template><script setup lang="ts">
const id = Math.random();
</script>

在这个场景中我们需要生成一个随机数id,在普通的客户端渲染中这个代码是没问题的。

但是如果这个代码是在SSR服务端渲染中那么就会报警告了,如下图:
useId

上面报错的意思是服务端和客户端生成的id不一样,因为服务端和客户端都执行了一次Math.random()生成id。由于Math.random()每次执行的结果都不同,自然服务端和客户端生成的id也不同。

useId函数的作用就是为了解决这个问题。

当然useId也可以用于客户端渲染的一些场景,比如在列表中我们需要一个唯一键,但是服务端又没有给我们,这时我们就可以使用useId给列表中的每一项生成一个唯一键。

Lazy Hydration  懒加载水合

异步组件现在可以通过 defineAsyncComponent() API 的 hydrate 选项来控制何时进行水合。(欧阳觉得这个普通开发者用不上,所以就不细讲了)

data-allow-mismatch

SSR中有的时候确实在服务端和客户端生成的html不一致,比如在DOM上面渲染当前时间,代码如下:

<template><div>当前时间是:{{ new Date() }}</div>
</template>

这种情况是避免不了会出现前面useId例子中的那种警告,此时我们可以使用data-allow-mismatch属性来干掉警告,代码如下:

<template><div data-allow-mismatch>当前时间是:{{ new Date() }}</div>
</template>

Custom Element 自定义元素改进

这个欧阳也觉得平时大家都用不上,所以就不细讲了。

Teleport组件新增defer延迟属性

Teleport组件的作用是将children中的内容传送到指定的位置去,比如下面的代码:

<div id="target"></div>
<Teleport to="#target">被传送的内容</Teleport>

文案被传送的内容最终会渲染在id="target"的div元素中。

在之前有个限制,就是不能将<div id="target">放在Teleport组件的后面。

这个也很容易理解DOM是从上向下开始渲染的,如果先渲染到Teleport组件。然后就会去找id的值为target的元素,如果找不到当然就不能成功的将Teleport组件的子节点传送到target的位置。

在3.5中为了解决这个问题,在Teleport组件上新增了一个defer延迟属性。

加了defer延迟属性后就能将target写在Teleport组件的后面,代码如下:

<Teleport defer to="#target">被传送的内容</Teleport>
<div id="target"></div>

defer延迟属性的实现也很简单,就是等这一轮渲染周期结束后再去渲染Teleport组件。所以就算是target写在Teleport组件的后面,等到渲染Teleport组件的时候target也已经渲染到页面上了。

useTemplateRef函数

vue3中想要访问DOM和子组件可以使用ref进行模版引用,但是这个ref有一些让人迷惑的地方。

比如定义的ref变量到底是一个响应式数据还是DOM元素?

还有template中ref属性的值明明是一个字符串,比如ref="inputEl",怎么就和script中同名的inputEl变量绑到一块了呢?

3.5中的useTemplateRef函数就可以完美的解决了这些问题。

这是3.5之前使用ref访问input输入框的例子:

<input type="text" ref="inputEl" />const inputEl = ref<HTMLInputElement>();

这个写法很不符合编程直觉,不知道有多少同学和欧阳一样最开始用vue3时会给ref属性绑定一个响应式变量。比如这样::ref="inputEl"

更加要命的是这样写还不会报错,就是inputEl中的值一直是undefined

最后一番排查后才发现ref属性应该是绑定的变量名称:ref="inputEl"

使用useTemplateRef函数后就好多了,代码如下:

<input type="text" ref="inputRef" />const inputEl = useTemplateRef<HTMLInputElement>("inputRef");

使用useTemplateRef函数后会返回一个ref变量,useTemplateRef函数传的参数是字符串"inputRef"

在template中ref属性的值也是字符串"inputRef",所以useTemplateRef函数的返回值就指向了DOM元素input输入框。这个比3.5之前的体验要好很多了,详情可以查看我之前的文章: 牛逼!Vue3.5的useTemplateRef让ref操作DOM更加丝滑

总结

对于开发者来说Vue3.5版本中还是新增了许多有趣的功能的,比如:onEffectCleanup函数、onWatcherCleanup函数、pauseresume方法、watchdeep选项支持传入数字、useId函数、Teleport组件新增defer延迟属性、useTemplateRef函数。

这些功能在一些特殊场景中还是很有用的,欧阳的个人看法还是得将Vue升到3.5。

关注公众号:【前端欧阳】,给自己一个进阶vue的机会

另外欧阳写了一本开源电子书vue3编译原理揭秘,看完这本书可以让你对vue编译的认知有质的提升。这本书初、中级前端能看懂,完全免费,只求一个star。

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

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

相关文章

浏览器串口助手插件,web版本串口调试助手浏览器插件 Web Serial Online 发布

Web Serial Online:串口调试的新时代 在数字化不断进步的今天,开发者和工程师面对单片机如ESP8266、ESP32以及RS485设备的调试任务时,往往需要便捷而高效的工具。我们最近推出的浏览器插件——Web Serial Online,旨在简化这一流程,提供一个无缝且直观的解决方案。 即插即用…

chatgpt中的公式复制到word的方法

chat辅助确实很有用。不论是出文稿还是代码。如何把chatgpt中的公式直接复制到word中且保持原样格式呢? 一、首先复制chatgpt里面的公式二、粘贴在下面网站 网站:Mathpix Accounts https://accounts.mathpix.com/login?return_to=https%3A%2F%2Fsnip.mathpix.com%2Fhome三、…

海外合规|新加坡网络安全认证计划简介(三)-Cyber Trust认证

一、 认证简介: Cyber Trust标志是针对数字化业务运营更为广泛的组织的网络安全认证。该标志针对的是规模较大或数字化程度较高的组织,因为这些组织可能具有更高的风险水平,需要他们投资专业知识和资源来管理和保护其 IT 基础设施和系统。Cyber Trust 标志采用基于风险的方法…

专升本,从已读不回,到冲进数字马力!

大家好,我是R哥。 最近做面试辅导,帮到了太多小伙伴入职了,大多都是统招「二本」及以上学历,其实也有好些个「大专」、「专升本」学历辅导入职的案例。 之前分享了一个大专学历成功上岸的 case:大专学历,快 30 岁,裁员 2 个月,拿到 25k+ 的 Offer,优秀!!今天再分享一…

PnFn信息点信息类工具类

数据单元标识定义信息点 DA 由信息点元 DA1 和信息点组 DA2 两个字节构成。DA2 采用二进 制编码方式表示信息点组,DA1 对位表示某一信息点组的 1~8 个信息点,以此 共同构成信息点标识 Pn(256*8: n=1~2040) 信息点当 DA1 和 DA2 全为“0”时,表示终端信息点,用 P0 表示;信息…

UDT(一):概览

1. 参考链接官网https://udt.sourceforge.io/谷博士对UDT的简单介绍https://udt.sourceforge.io/doc/udt-2009.ppt获取UDT源码https://sourceforge.net/projects/udt/files/udt/4.11/udt.sdk.4.11.tar.gz/download?use_mirror=pilotfiberUDT讨论贴https://sourceforge.net/p/u…

南沙信C++陈老师解一本通题:1075:药房管理

​题目描述】随着信息技术的蓬勃发展,医疗信息化已经成为医院建设中必不可少的一部分。计算机可以很好地辅助医院管理医生信息、病人信息、药品信息等海量数据,使工作人员能够从这些机械的工作中解放出来,将更多精力投入真正的医疗过程中,从而极大地提高了医院整体的工作效…

跨越网络边界:内外网数据摆渡最优方案!

随着网络技术的演进,网络攻击、数据窃取、数据泄露事件也愈发频繁,给企业造成损失和负面影响,企业数据防泄漏治理是大趋势,也是自身迫切需求。网络隔离技术作为网络安全和数据安全的重要保障手段被广泛应用到各个行业领域,对于金融行业,国家出台的《金融行业信息系统信息…

推荐一款开源、高效、灵活的Redis桌面管理工具:Tiny RDM!支持调试与分析功能!

1、引言 在大数据和云计算快速发展的今天,Redis作为一款高性能的内存键值存储系统,在数据缓存、实时计算、消息队列等领域发挥着重要作用。然而,随着Redis集群规模的扩大和复杂度的增加,如何高效地管理和运维Redis数据库成为了许多开发者和运维人员面临的挑战。Tiny RDM(T…

河道漂浮物识别 智慧水利 智慧水务

河道漂浮物识别根据智能视频分析,漂浮物检验报警设备自动分析识别视频图像信息内容,不用人工干涉;河道漂浮物识别监控区域里的河面漂浮物,出现异常状况时更快开展预警信息,真真正正完成预警信息、正常的检验、规范化管理,合理帮助管理者最大限度地降低乱报和少报;还能够…

智慧港口安全预警AI智能视频分析平台

智慧港口安全预警AI智能视频分析平台,各种算法识别精度达到90%以上,实现对动火作业的智能化全过程监管,减少港口安全事故发生的可能性,智慧港口安全预警AI智能视频分析平台紧跟港口物流智能化视频分析平台的发展趋势,从人力监管模式转变为高效、精准的智能化监管模式,提高…

工地安全帽佩戴识别

工地安全帽佩戴识别根据安装在现场施工工地的各种各样监控系统,创建智能监管和防护系统软件,开展面部识别、个人行为识别和安全帽子识别,工地安全帽佩戴识别合理填补施工现场监管中传统式方式和技术性的缺点,真真正正完成预警信息、正常的检验、规范化管理。工地安全帽佩戴…