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

带你了解Vue3.0的七大亮点

时间:2023-03-15 08:13:58 科技观察

一、性能比2.x快1.2到2倍diff算法的优化vue2中对virtualdom进行了全量对比。在vue3中,增加了静态标签PatchFlag。在创建vnode时,会根据vnode的内容是否可以更改,为其添加一个静态标签PatchFlag。比较时,只会比较具有PatchFlag的节点。PatchFlag有一个类型,比如一个可变的文本节点,它会被添加一个staticflag,它的PatchFlag枚举值为TEXT。这样,diffing时只需要比较文本内容即可。比较的内容比较少。PatchFlag还有动态类、动态样式、动态属性、动态key属性等枚举值。渲染阶段的静态提升(渲染阶段是指生成虚拟dom树的阶段)。在vue2中,一旦检测到数据变化,就会重新渲染组件,重新创建所有vnode,形成新的vdom树。在vue3中,对于不参与更新的vnode,会静态提升,只创建一次,重新渲染时直接复用。静态提升可以理解为在第一次渲染不参与更新的vnode节点时保存它们的引用。当重新渲染一棵新的vdom树时,直接获取它们的引用即可,无需重新创建它们。vue2中缓存了事件监听器,我们写的@click="onClick"也算是一个动态属性,diffing的时候要对比一下。但是我们知道它不会改变,比如变成@click="onClick2",绑定其他值。在vue3中,如果事件没有变化,onClick会被缓存(类似于静态提升达到的效果),节点不会被PatchFlag标记(即不需要更新的节点)。这样在render和diff两个阶段,事件监听属性就省去了不必要的性能消耗。我曾经用一个巨大的dom树来维护一个页面。既然有这么多节点,那么也有很多节点不需要参与更新。在使用vue2的情况下,大量的性能消耗在render和diff这两个阶段。如果当时有vue3,我觉得性能会优化很多。减少创建组件实例的开销。vue2.x每次创建一个实例,数据、props、computed都会暴露在this上,这些都是由Object.defineProperty定义的。这部分操作相当耗时。基于vue3.0中的Proxy,降低了创建组件实例的性能开销。2、按需编译,体积比Vue2.x更小(Treeshaking)在vue3中,可以参考Vue的功能如下。如果你的项目不使用watch,那么treeshaking将在编译期间被移除。import{computed,watch,nextTick}from"vue";使用ES6模块系统导入/导出。3.CompostionAPI:CompositionAPI/InjectionAPI这里需要说一下代码的组织方式。传统网页以html/css/javascript(结构/样式/逻辑)分隔。Vue/React将紧密相关的结构/样式/逻辑以组件化的方式放在一起,有利于代码维护。Compostionapi更进一步,专注于JavaScript(逻辑)部分,将逻辑相关的代码放在一起,方便代码维护。在vue2组件中,代码以OptionAPI风格组织(data/methods/mounted),这样会造成逻辑分散。例如,当我们完成一个计数器功能时,我们必须在data中声明变量并在methodsResponse函数中定义它们,在mounted中初始化变量。如果要在一个功能多、代码量大的组件中维护这样的功能,需要反复切换到data/methods/mounted中对应的位置,然后进行codeChange。在vue3中,使用setup函数。如下图,count相关的逻辑放在counter.js文件中,todo相关的逻辑放在todos.js中。importuseCounterfrom'./counter'importuseTodofrom'./todos'setup(){let{val,todos,addTodo}=useTodo()let{count,add}=useCounter()return{val,todos,addTodo,count,add,在我看来,这是CompostionAPI最大的特点,代码以函数为单位组织的方式。同时它使代码更易于重用。说到重用,CompostionAPI的方式要比mixin的方式好很多。可以清楚的看到组件使用的数据和方法来自于哪个模块,而组件中mixin的功能往往让我们搞不清这个函数来自于哪个mixin。四、更好的TS支持Vue2不适合用ts,因为vue2的OptionAPI风格。options是一个简单的对象,而ts是一个类型系统,面向对象的语法。两者有点不匹配。在结合vue2和ts的具体实践中,我们需要使用vue-class-component加强vue组件,让脚本支持TypeScript装饰器,使用vue-property-decorator添加更多结合Vue特性的装饰器,最后创建ts组件写法和js组件的写法有很大区别。vue3中特制了defineComponent函数,让组件在ts下更好的使用参数类型推断。在CompositionAPI代码风格中,比较有代表性的API是ref和reactive,它们也很好地支持类型声明。import{defineComponent,ref}from'vue'constComponent=defineComponent({props:{success:{type:String},student:{type:ObjectasPropType,required:true}},setup(){constyear=ref(2020)constmonth=ref('9')month.value=9//OKconstresult=year.value.split('')//=>Property'split'doesnotexistontype'number'}五、自定义RenderingAPI(CustomRendererAPI)Vue2.x架构问题Vue2.x最初支持在浏览器中运行,渲染到浏览器的dom,随着vue的流行,出现了weex和myvueweex:移动端跨平台需要渲染的解决方案到移动端,weex是在原来的vue项目中写的,缺点是让原来的vue项目变大了,不是通用的解决方案myvue:用在小程序上,需要在小程序框架上渲染。myvue是单独fork一个源码进行修改,缺点也很明显。从fork的那一刻起,myvue中vue的版本就和官方不一致了。vue2.x的项目架构对这种不同平台的渲染不是很友好。Vue3.0引入了自定义渲染API来解决这个问题。我们先看下vue2和vue3入口的区别://vue2importVuefrom'vue'importAppfrom'./App.vue'newVue({=>h(App)}).$mount('#app')//vue3const{createApp}from'vue'importAppfrom"./src/App"createApp(App).mount(('#app')vue官方实现的createApp会为我们的模板映射生成html代码,但是如果你不想渲染生成为html,但是要渲染不是html的代码,比如canvas,那么就需要使用CustomRendererAPI,定义自己的render渲染生成函数。//你自己实现一个createApp,比如renderingtocanvas.import{createApp}from"./runtime-render";importAppfrom"./src/App";//根组件createApp(App).mount('#app');配合CustomRendererAPI,比如weex的myvue等解决方案的问题已经完美解决,重写createApp即可六、更高级的组件Fragment组件//vue2不允许这样写,组件必须有根节点,现在可以wr这样一来,vue就会为我们创建一个虚拟的Fragment节点。这样写有什么好处呢?首先,如果不需要根节点,则无需创建,减少了节点数量。其次,Fragment节点是虚拟的,不会在DOM树中呈现。Suspense组件Loading...在Suspended-component完全渲染之前,将显示回退内容。如果是异步组件,Suspense可以等待组件下载完成,或者在setup函数中进行一些异步操作。7、更快的开发体验(vite开发构建工具)使用webpack作为开发构建工具时,npmrundev会需要等待一段时间,而且项目越大,等待时间越长。hotreload页面有几秒的延迟,但是如果你用vite作为vue3的开发构建工具,npmrundev秒打开,hotreload也会很快。这样的开发体验真的很爽,拒绝等待。vite的原理还是利用浏览器支持import关键字。启动项目不需要先用webpack构建工具构建。浏览器直接请求路由对应的代码文件,代理服务器编译返回单个文件。如果请求文件中导入了其他文件,浏览器继续发送请求,代理服务器返回。这样在执行npmrundev时不需要编译,实时请求实时编译。小结:另外,数据监控方式变成了Proxy,消除了Object.defineProperty现有的局限性(比如无法检测新属性的添加),提供了更好的性能。Vue3解决了vue2的一些问题,比如大型应用的性能问题,不友好的ts支持,自定义渲染API来解决架构的问题。如果在vue3的基础上实现weex框架会好很多。也做了很多优化,CompostionAPI让代码更有条理。vite开发构建工具让开发体验更好,Treeshaking让包更小,性能更好。总的来说vue3还是很不错的,带来了很多很好的新特性。