This is the 15th day of my participation in the genwen Challenge

The following three decorators are all implemented using async/await to transform async into synchronization.

Methods that require to be decorated must be written async/await, which is very convenient to use and the implementation is completely hidden inside the decorator.

The first two are used in vUE for class notation in ts environment. However, once you look at the logic, you can easily modify it to work with VUE components in your JS environment.

1. Add a variable to vue indicating that initialization is complete.

The initialization logic related to the business is complete, such as the search function: show in searchloadingIf the result is null, no data is displayed. But the first time you open the page, the search is not complete, but it’s not appropriate to say that there’s no data at the moment and you need a variable like this to handle the boundary casetsUnder the environment ofvue

Add this property through a decorator and wrap vue’s Created, Mounted, and beforeDestroy methods. When a created or Mounted request completes, set pageIsReady to True. When using this decorator, there is no sense in the business code, no mental burden whatsoever.

import { Constructor } from"vue/types/options";
exporttype WrapReadyProperty<T> = T & { pageIsReady? : boolean }/ * * *@compontent After using this decorator, the component will be injected with the property pageIsReady. PageIsReady becomes true when both Created and Mounted are completed. Mounted or Created is async/await. (Depending on which method the request is made to initialize the component) * It can then be used directly in the template. * Use the isPageReady. Call (this) method in script; * /
exportdefaultfunction PageReadyStatus() {
    let createdDone = false;
    let mountedDone = false;
    function isCreatedMountedAllDone() {
        return createdDone && mountedDone;
    }
    returnfunction pageReadyEnhancement<T extends Constructor>(target: T) {
        const oldMounted = target.prototype.mounted || function() {}const oldCreated = target.prototype.created || function() {}const oldBeforeDestroy = target.prototype.beforeDestroy || function() { }
        target.prototype.pageIsReady = false;
        target.prototype.created = asyncfunction(. params: any[]) {
            await oldCreated.apply(this, params);
            createdDone = true;
            this.pageIsReady = isCreatedMountedAllDone()
        }
        target.prototype.mounted = asyncfunction(. params: any[]) {
            await oldMounted.apply(this, params);
            mountedDone = true;
            this.pageIsReady = isCreatedMountedAllDone()
        }
        target.prototype.beforeDestroy = asyncfunction(. params: any[]) {
            await oldBeforeDestroy.apply(this, params);
            mountedDone = false;
            createdDone = false;
            this.pageIsReady = false;
        }
        return target
    };
}

exportfunction isPageReady(this: WrapReadyProperty<Vue>) {
    returnthis.pageIsReady
}
Copy the code

2. Add anti-shock and loading styles to the event callback function and button Dom

Used fortsUnder the environment ofvue

The process of being decorated by wrapping a decorator. The request is wrapped async/await. This way you only need to use an await inside the decorator to know if the wrapped method has finished executing. At the same time, you can take the clicked DOM element from the event object and modify it.

/* * Make sure that the argument list for the wrapped method ends with the argument for the click event */
exportdefaultfunction buttonThrottle() {
    let pending = false;
    returnfunction(target: any, name: string): any {
        const btnClickFunc = target[name];
        const newFunc = asyncfunction(this: Vue, ... params: any[]) {
            if (pending) {
                return;
            }
            const event:Event = params[params.length - 1];
            let btn = event.target as HTMLElement
            pending = true;
            const recoverCursor = changeCursor(btn);
            try {
                await btnClickFunc.apply(this, params);
            } catch (error) {
                console.error(error);
            }
            recoverCursor();
            pending = false;
        };
        target[name] = newFunc;
        return target;
    };
}
function changeCursor(btn? : HTMLElement) {
    if (btn == null) {
        return() = > {};
    }
    const oldCursor = btn.style.cursor;
    btn.style.cursor = "wait";
    return() = > {
        btn.style.cursor = oldCursor;
    };
}

Copy the code

Usage: Use this decorator on the click event function. The decorator automatically detects that the function is complete and adds the Point: Wait attribute to the BUTTON’s Dom node during execution

import { Component, Vue } from"vue-property-decorator";
    import buttonThrottle from"@/ui/view/utils/buttonThrottle";

    type Member = { account_no: string; name: string; warn? : string }; @Component({components: {} })
    exportdefaultclass AddMemberInput extends Vue {        @buttonThrottle()
        private async confirmAdd() {
            awaitthis.addMembers(this.getVaildMembers()); }}Copy the code

3. Mounted Displays a blank screen

Objects that wrap vUE in THE VUE for JS

/ / get mounted or created with async/await, then get the root of the component with this pointing to vue power, and modify it as needed. The following code just hides the component. In fact, you can write more complex logic and display something else during loading. Do what you want.

function firstPaintControl(vueObj) {
    let oldMounted = vueObj.mounted || function() {};
    vueObj.mounted = asyncfunction(. params) {
      this.$el.style.visibility = 'hidden';
      await oldMounted.apply(this, params);
      this.$el.style.visibility = 'visible';
    };
    return vueObj;
  }
Copy the code