当前位置: 首页 > Web前端 > vue.js

关于Vue3和Ts的心得和思考

时间:2023-04-01 00:42:32 vue.js

作者:京东物流吴运阔1前言Vue3正式发布有一段时间了,各种生态已经成熟。最近在用taro+vue3重构冷链小程序。经过一段时间的开发和使用,有了自己的一些想法。总的来说,Vue3无论是在底层原理上,还是在实际开发过程中,都取得了长足的进步。从源码层面,使用Proxy代替Object.definePropertyAPI,一是代理对象,二是递归监控属性,这样性能有了很大的提升,同时也解决了对象动态属性的问题增加,数组改变监控中的缺陷;优化diff算法,增加静态标签,大幅提升Vue的执行效率;还有静态改进、事件监听缓存等一系列提高效率的方法。从应用层面来说,主要的变化是将optionAPI改为compositionAPI(组合API),摒弃了业务中数据、方法、生命周期函数的开发方式,让代码与业务的关联性更强业务融合在代码开发、代码阅读、代码维护等方面对开发者更加友好。对打字稿有更好的支持。我们知道对于大型前端项目,使用TypeScript类型验证可以让前端项目更加健壮,这也让Vue3为大型项目的开发提供了更多的支持。强大的质量保证。2组合API所谓组合API,是将Vue2中的数据、方法、生命周期、数据监控等选项封装成钩子函数,然后组合到setup函数中。setup函数的核心是setup函数。设置函数的目的就是要使用这些新组合的API,而这些API只能在设置函数中使用。setup函数执行的时机是props初始化之后,beforeCreate函数执行之前,所以执行setup时,vue实例还没有初始化,所以不能在setup中使用this对象。setup函数的返回值会被注入到Vue实例中供Vue组件使用,所以任何想要在Vue组件的模板中使用的数据都必须在setup函数中返回。组合API的组合体现在两个层面。第一层,就是把某个业务相关的数据和处理逻辑放在一起。这是一个关注点的聚合,更方便我们编写代码和处理业务逻辑,可以更专注于业务逻辑,更方便我们看代码。第二层是指当某个组件的业务逻辑足够复杂,setup中的代码足够多时,我们可以进一步抽取setup内部相关的一块业务,让代码逻辑更加清晰,达到进一步聚合的效果。如下代码所示,如??果提取了业务代码块A,那么代码块A中返回的数据就可以在组件中使用了://componentimportfunctionAfrom'A'exportdefaultdefineComponent({name:'componentName',setup(){...functionA()}})//代码块Aexportdefault()=>{return{a:1}}3ReactiveAPIVue3中的reactiveAPI主要体现在ref和reactivefunction上。关于反应式API,我想问两个问题。第一个是为什么要加入反应式API,第二个是反应式API函数ref和reactive的异同点。3.1为什么要添加响应式API?在Vue2中,所有的数据都写在data的option中,data中的数据是响应式的。出现的一个问题是一些常量数据本身不需要监控,造成了资源的浪费。.因此,Vue3中添加了响应式API。它只需要响应dom中需要动态更新的数据,dom中不需要动态更新的数据不做响应式处理,很大程度上节省了资源。这里我觉得需要注意的是,在写代码的时候一定要仔细思考哪些数据需要响应式绑定,哪些数据不需要响应式绑定,而不是一个脑子把它们都绑定起来,这样即使code的逻辑不能很清晰易懂,也会影响执行效率(写惯Vue2的同学需要注意)。3.2ref和reactive的异同在理解了为什么要加入响应式API之后,我们发现Vue3提供了两个响应式API函数,ref和reactive。为什么提供两个API?一个人做不到吗?那么这两个API有什么区别呢?在使用层面,ref绑定的数据需要使用[data].value来改变数据。reactive绑定的数据需要使用[data].[prpoerty]来改变数据。从使用场景来说,一般对于单个普通数据,我们使用ref来定义响应性。对于复杂的数据,比如:表单数据对象,某个模块的一组数据等,使用reactive来定义响应性。那么,对象是不是一定要用reactive来定义呢?其实没有,没关系。官方的说法是:大家可以根据自己的习惯使用不同的API。其实我觉得他们都有自己的使用场景。ref强调的是数据值的变化,reactive强调的是数据中某个属性的变化。4treeShaking思路当一个Javascript项目达到一定规模时,将代码分成模块会更容易管理。但是,这样做时,我们可能最终会导入未实际使用的代码。TreeShaking是一种通过消除最终文件中未使用的代码来优化大小的方法。Vue3使用treeshaking方法分离组件及其所有生命周期函数。如果组件中使用的代码不会出现在最终的打包文件中,这将大大减少Vue3项目的打包体积。其结果之一是使用方法不同。4.1如何使用生命周期函数import{defineComponent,ref,onMounted}from'vue';exportdefaultdefineComponent({name:'Gift',setup(){constcounter=ref(0);onMounted(()=>{//处理业务,通常是数据请求})return{counter}}})4.2如何使用Vuex从“vuex”导入{useStore};从'vue'导入{defineComponent,ref,computed};exportdefaultdefineComponent({name:'Gift',setup(){constcounter=ref(0);conststore=useStore();conststoreData=computed(()=>store);//配合computed得到商店的价值。return{counter,storeData}}})4.3如何使用路由器({name:'Gift',setup(){constcounter=ref(0);constrouter=useRouter();constonClick=()=>{router.push({name:"AddGift"});}return{counter,onClick}}})5Typescript的使用这部分讲的是Ts,但是和Vue3的开发是息息相关的。Vue3是整体使用Ts写的。所以Vue3项目的开发需要用到Ts,所以我们还是要了解TS。关于Ts的使用我这里就不细说了。这里想说的是在实际业务场景中如何组织Ts代码。通过对TS的大量使用,我的一个体会是:Ts的核心思想是先关注数据结构,然后根据数据结构开发页面。以前的前端开发模式是先写页面,再专注于数据。比如我们要开发一个页面,可能需要先定义一些接口。在开发页面时要注意:页面数据的接口、接口返回的数据类型、请求参数的类型等。下面是开发列表页的例子://这是列表接口中每一项的数据类型IDataItem{id:string|number;name:string;desc:string;[key:string]:any;}//接口返回值类型,一般情况下,我们无法确定接口返回的数据类型,所以使用泛型接口IRes{code:number;msg:string;data:T}//端口返回数据类型定义接口IDataInfo{list:Array;pageNum:number;pageSize:number;total:number;}//请求导出constgetDatalist=(params:Record):Promise>=>{returnHttp.get("/api/data/list",params);};如上面的代码,当我们的接口定义完成后,我们的页面数据就基本清晰了,直接写页面会清晰很多,出错的概率也会大大降低。