当前位置: 首页 > 科技观察

【科普】Vue3更新了什么?

时间:2023-03-13 14:15:19 科技观察

Vue3已经发布一段时间了。这个版本从底层实现到顶层API设计都有很大的变化,但是具体有哪些变化呢?简单盘点一下:1.CompositionAPI采用传统的option配置方式编写组件的问题是随着业务的复杂度越来越高,代码量会不断增加;因为相关业务的代码需要根据option的配置写入特定区域,后续维护非常复杂,而且代码可复用性不高,composition-api就是为了解决而诞生的这个问题。《1.1OptionsAPI的问题》在使用传统的OptionsAPI时,如果增加或修改需求,需要分别在data、methods和computed中修改。当业务逻辑和功能增长时,理解和维护复杂的组件变得困难。《1.2CompositionAPI的优点》和Vue3的compositionAPI把每一个功能点都抽离成一个函数,这样我们就可以更优雅的组织我们的代码。让相关功能的代码更有序的组织在一起。《1.3Reactivevsref》在vue2.x中,data是在data.h中定义的。但是Vue3.x可以使用reactive和ref来定义数据。那么ref和reactive有什么区别呢?从原理上看:ref用于创建一个包含响应式数据的引用对象。接收到的数据可以是:基本数据类型、对象类型。基本数据类型:Response仍然是通过object.defineProperty()的get和set完成的。对象类型:内部帮助vue3.0中一个新的函数reactive函数是通过proxy实现的。源码地址:https://github.com/vuejs/vue-next/blob/master/packages/reactivity/src/ref.ts。Reactive用来定义:对象和数组通过Proxy实现响应性(数据劫持),通过Reflect操作源对象内部的数据。从使用上看:ref:定义的数据,操作数据需要.value,读取数据时模板中不需要.value,直接使用即可。reactive定义的数据:操作数据和读取数据:都不需要.value。1.4新增watchEffect函数watch函数需要指定被监控的属性,在回调函数中执行。默认情况下,回调仅在监听的源数据发生变化时执行。也可以加上immediate:true使其立即生效。watchEffect不需要指定监听哪个属性,在监听回调中使用哪个属性。//只要watchEffect指定的回调中使用的数据发生变化,就会直接重新执行回调。watchEffect(()=>{constx1=sum.valueconstx2=person.ageconsole.log('watchEffecthasexecutedacallback')})二、VDOM优化前重写VirtualDom的diff算法,需要遍历所有节点,并且每个节点都要比较旧的道具和新的道具是否发生了变化。在Vue3.0中,只有带有PatchFlag的节点才会被真正追踪。在后续的更新过程中,Vue不会跟踪静态节点,只会跟踪带有PatchFlag的节点,以加快渲染速度。

vue{{msg}}{{msg}}
导出函数render(_ctx,_cache,$props,$setup,$data,$options){return(_openBlock(),_createBlock(span,null,[_createVNode(span,null,vue),_createVNode(span,null,_toDisplayString(_ctx.msg),1/*TEXT*/),_createVNode(span,{id:_ctx,helloclass:bar},_toDisplayString(_ctx.msg),9/*TEXT,PROPS*/,[id])}源码中above1/*TEXT*/这个标记是PatchFlag,Vue只会跟踪第二个和第三个有PatchFlag的节点,在第三个span标签中,PatchFlag变成9/*TEXT,PROPS*/,[id],提醒我们有这个dom元素中不仅TEXT变了,PROPS也可能变了,后面数组里面的内容是一个可能变的属性,静态添加的class没有标注,因为dom元素的static属性是在已经创建的渲染时不会改变,以后更新时,diff算法不会关心它。3.R响应式实现3.1Vue2.x的响应式vue官方文档:https://cn.vuejs.org/v2/guide/reactivity.html。实现原理:对象类型:通过Object.defineProperty()拦截读取和修改属性(数据劫持)。数组类型:通过重写更新数组的一系列方法来实现拦截。(改变数组的方法被包裹)。Object.defineProperty(data,'count',{get(){},set(){}})有一个问题:添加或删除属性时界面不会更新。无法监听数组下标和长度的变化。不支持Map、Set、WeakMap和WeakSet。3.2Vue3.0响应式实现原理:Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ProxyReflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ReflectthroughProxy(代理):拦截对象中任意属性的变化——读写属性值,添加属性,删除属性等。通过Reflect(反射):操作源对象的属性。MDN文档中对Proxy和Reflect的描述:newProxy(data,{//拦截读取属性值get(target,prop){returnReflect.get(target,prop)},//拦截设置属性values或添加新的属性set(target,prop,value){returnReflect.set(target,prop,value)},//拦截删除属性deleteProperty(target,prop){returnReflect.deleteProperty(target,prop)}})proxy.name='tom'4.新的生命周期钩子去掉了vue2.0中的beforeCreate和created阶段,增加了新的setup。执行设置时,组件实例尚未创建。每个生命周期函数都必须导入才能使用,所有生命周期函数都需要在setup中使用。destroyed重命名为unmounted;beforeDestroy重命名为beforeUnmount。5.新组件《5.1片段(Fragment)》Vue2:组件必须有根标签。Vue3:组件可以没有根标签,可以直接写多个根节点,多个标签会被包含在一个Fragment虚拟元素中。好处:减少标签层级,减少内存占用,提高渲染性能。5.2TeleportTeleport就像一个“任意门”,将包组件html结构传送到任意指定的地方。比如我们在日常开发中经常会用到弹窗组件,而Dialog组件会被渲染成层层叠叠的子组件,样式和位置处理起来非常困难。这时候我们就希望将组件挂载到body上,更方便的控制Dialog的样式。简单来说,我们希望在组件内部继续使用Dialog,同时也希望渲染的DOM结构不嵌套在组件内部的DOM中。它可以使用,它可以创建一个入口,将Dialog渲染的内容传递到body上,而不改变组件内部元素的父子关系。

Popup

关闭弹出窗口
5.3Suspense在等待异步组件时渲染一些额外的内容,让应用有更好的用户体验。它提供了两个模板插槽。一开始会渲染fallbackslot下的内容,达到一定条件才会渲染defaultslot的官方内容。使用Suspense组件更容易显示异步渲染。

加载中......