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

使用async-await实现一些装饰器,让Vue更好用

时间:2023-03-31 15:51:40 vue.js

async/await加上装饰器会产生神奇的效果。下面列出的装饰器都要求被装饰的方法写成async/await,这样可以利用async/await的特性从方法外部知道异步方法是否完成。这样就可以将复杂麻烦的逻辑隐藏在装饰器内部,让业务代码更加简洁。下面的装饰器,除了最后一个,都是Vue在Typescript环境下类写法中用到的。最后一个其实不是装饰器,而是高阶函数,但是众所周知,装饰器本质上是一个高阶函数。所以所有的装饰器都可以方便的改成高阶函数,然后在js环境下的vue中使用。在vue中添加一个变量,表示初始化完成。示例使用场景:搜索页面:搜索时显示loading,结果为空时不显示任何数据。首次打开页面时,在created或mounted中发送请求以执行初始搜索。这个时候搜索还没有完成,显示还没有数据是不合适的。这时候就需要一个变量来判断页面是否是第一次打开。代码解释:通过装饰器在组件类中添加该属性(pageIsReady),将vue的created、mounted、beforeDestroy方法进行包装,以监控组件的生命周期。当created或mounted中发送的请求完成后,将pageIsReady设置为true。然后在beforeDestroy中重置状态,因为装饰器使用了闭包,所以只会被实例化一次。import{Constructor}from"vue/types/options";exporttypeWrapReadyProperty=T&{pageIsReady?:boolean;createdDone?:布尔值;mountedDone?:boolean}/***在@component之后使用这个装饰器,*组件会被注入pageIsReady属性,*当created和mounted都被执行时pageIsReady变为true,*要求mounted或created是async/await。(取决于请求是通过哪种方式初始化组件)*然后就可以直接在模板中使用了。*在脚本中使用调用isPageReady.call(this)方法;*/exportdefaultfunctionPageReadyStatus(){returnfunctionpageReadyEnhancement>(target:T){constoldMounted=target.prototype.mounted||函数(){}constoldCreated=target.prototype.created||函数(){}constoldBeforeDestroy=target.prototype.beforeDestroy||function(){}target.prototype.pageIsReady=false;函数isCreatedMountedAllDone(this:T){return!!this.createdDone&&!!this.mountedDone;}target.prototype.created=asyncfunction(...params:any[]){awaitoldCreated.apply(this,params);this.createdDone=true;this.pageIsReady=isCreatedMountedAllDone.call(this)}target.prototype.mounted=asyncfunction(...params:any[]){awaitoldMounted.apply(this,params);这个.mountedDone=truethis.pageIsReady=isCreatedMountedAllDone.call(this)}target.prototype.beforeDestroy=asyncfunction(...params:any[]){awaitoldBeforeDestroy.apply(this,params);this.createdDone=false;这个.mountedDone=true这个.pageIsReady=false;}returntarget};}exportfunctionisPageReady(this:WrapReadyProperty){returnthis.pageIsReady}用法在类上使用这个装饰器@Component({components:{}})@PageReadyStatus()exportdefaultclassIndexextendsVue{@buttonThrottle()privateasyncconfirmAdd(){等待this.addMembers(this.getVaildMembers());}}在模板中使用pageIsReady变量为事件回调函数和按钮Dom添加防抖和加载样式使用场景示例:点击一个按钮,触发一个函数,发送请求这时候需要对这个函数进行防抖,并且在按钮中添加一个loading样式的代码来说明使用async/await将异步转为同步的特性,当该方法在要执行的装饰器中找到。并从时间对象中获取按钮的dom节点,改变按钮的样式。我用了一个cursor:wait;/**请确保包装方法的最后一个参数列表是点击事件的参数*/exportdefaultfunctionbuttonThrottle(){letpending=false;返回函数(目标:任何,名称:字符串):任何{constbtnClickFunc=target[name];constnewFunc=asyncfunction(this:Vue,...params:any[]){if(pending){return;}constevent:Event=params[params.length-1];让btn=event.targetasHTMLElementpending=true;constrecoverCursor=changeCursor(btn);尝试{awaitbtnClickFunc.apply(this,params);}catch(错误){console.error(错误);}恢复游标();待定=假;};目标[名称]=newFunc;返回目标;};}functionchangeCursor(btn?:HTMLElement){if(btn==null){return()=>{};}constoldCursor=btn.style.cursor;btn.style.cursor="等待";return()=>{btn.style.cursor=oldCursor;};}用法:在点击事件函数上使用这个装饰器。从“vue-property-decorator”导入{Component,Vue};从“@/ui/view/utils/buttonThrottle”导入buttonThrottle;typeMember={account_no:字符串;名称:字符串;警告?:字符串};@Component({components:{}})exportdefaultclassAddMemberInputextendsVue{@buttonThrottle()privateasyncconfirmAdd(){awaitthis.addMembers(this.getVaildMembers());}}}注入loading变量scene,在发送请求时给页面添加一个loading状态,比如element-ui加载说明中有一个v-该指令是否在加载中需要一个可变代码解释。向组件添加变量。变量名由参数variableName指定。变量在被包装的方法执行期间会为真,所以你不需要自己写this.loading=truethis.loading=falseexportdefaultfunctionFunctionLoadingVariable(variableName:string){returnfunction(target:any,name:string):any{target[变量名]=false;constbtnClickFunc=target[名称];constnewFunc=asyncfunction(this:Vue&{[key:string]:boolean},...params:any[]){try{this[variableName]=trueawaitbtnClickFunc.apply(this,params);}catch(错误){console.error(错误);}这个[变量名]=false};目标[名称]=newFunc;骨架屏。尤其是微信小程序,因为在加载完成之前非常难看,所以几乎所有的小程序在挂载之前都会白屏。通过async/await获取是否mounted或者created是执行的,然后通过this指向vue的力量获取组件的根节点,然后根据需要修改显示其他内容,毕竟你拿到了Dom,可以为所欲为你要。functionfirstPaintControl(vueObj){让oldMounted=vueObj.mounted||功能(){};vueObj.mounted=asyncfunction(...params){this.$el.style.visibility='hidden';等待oldMounted.apply(这个,参数);this.$el.style.visibility='可见';};返回vueObj;}