1. 程式人生 > 實用技巧 >vue3.0 decorators 修飾器 使用

vue3.0 decorators 修飾器 使用

Vue Pandora Decorators

  • npm i vue-pandora-decorators --save
  • yarn add vue-pandora-decorators

本外掛基於 VUE 3.0 開發

  • vuex 修飾器及 Composition API 支援
  • 面向物件 @Component 支援
  • 提供 @Mixin 繼承
  • 本外掛主要是用 Proxy 代理模式 代理 Vue Context

基礎使用

Component 修飾器使用 使用

  • components/test2.vue
<template>
    <div>Test2 ...</div>
    <div>{{aaa}}</div>
    <div>{{name}}</div>
    <div>{{object}}</div>
    <div>{{test}}</div>
    <div>{{computed}}</div>
    <el-button @click="()=>edit()">修改</el-button>
</template>
<script lang="ts">
import { ToRefs, watch } from 'vue';
import { Component, dynamic, Prop, PureComponent, Reactived, computed } from 'vue-pandora-decorator';

export interface Props {
    aaa: number;
}

export interface State {
    name: number;
    object: any;
}

// 這裡可以不定義 Props 和 State 預設 any
@Component
export default class Test2 extends PureComponent<Props, State> implements Reactived<State> {
    
    @dynamic
    public name: number;
    
    @dynamic
    public object: any;

    public test: boolean;

    @Prop
    public aaa!: number;

    @computed
    public get computed() {
        return `${(new Date).getTime()} ${this.aaa} ${JSON.stringify(this.object)}`;
    }

    constructor(props: any, ctx: any){
        super(props, ctx);
        this.name = 111;
        this.object = {};
        this.test = true;
        // // 下面兩種等同
        // console.log(this.aaa);
        // console.log(this.props.aaa);
    }

    // 開始生成響應式資料
    onReactived() {
        console.log(`on reactived ...`);
    }

    // 這裡 return 的資料會自動 merge 到 component
    public setup(props: any, ctx: any) {
    }

    // 在 setup 後 merge component 完成
    // 可選
    // public reactived() {
    // public reactived(data: ToRefs<this>) {
    public reactived(data: ToRefs<State>) {
        console.log(`reactived ...`);
    }

    // 資料初始化完成 返回到 上下文之前
    // 未定義 State
    // public didReactived(data:ToRefs<this>) {
    // 以定義 State
    public didReactived(data: ToRefs<State>){
        // 下面兩種等同
        // watch(this.state.name, ()=>{
        //     console.log(`監聽修改 ...`);
        // });
        watch(data.name, ()=>{
            console.log(`監聽修改 ...`);
        });
        console.log(`did reactived ...`);
        // 這裡一可以 return 初始資料
        return data;
    }

    public edit() {
        console.log(11111, this.name, this.test);
        this.name++;
        this.object.time = (new Date).getTime();
        this.test = !this.test;
    }

    public editProps(){
        this.aaa += 100;
    }
}
</script>
  • 繼承 使用 component/test3.vue
<template>
    <div>Test3 ...</div>
    <div>{{name}}</div>
    <div>{{object}}</div>
</template>
<script lang="ts">
import { Component, Mixin } from 'vue-pandora-decorators';
import Test2 from './test2.vue';

@Component
export default class extends Mixin(Test2) {
}
</script>
  • 不使用修飾器 home.vue
<template>
    <div>Dec ...</div>
    <div>{{name}}</div>
    <div>{{object}}</div>
    <test2 :aaa="aaa"></test2>
    <test3></test3>
</template>
<script lang="ts">
import { reactive, ref } from 'vue';
import Test1 from './components/test1.vue';
import Test2 from './components/test2.vue';
import Test3 from './components/test3.vue';

export default {
    components: {
        Test1,
        Test2,
        Test3,
    },
    setup() {
        const aaa = ref(333);
        setInterval(()=>{
            aaa.value ++;
        }, 1000);
        return { name: ref(111), object: reactive({}), aaa }
    }
}
</script>

vuex 修飾器使用

  • 全域性 dynamic 模式
  • 入口 store/index.ts
import { createStore } from 'vuex';
import { PermissionState } from './modules/permission';

export interface IRootState {
    permission: PermissionState;
}

export default createStore<IRootState>({});
  • store/modules/permission.ts

import { VuexModule, Module, Action, Mutation, getModule } from 'vue-pandora-decorators';
import store from '/@/store';

export interface PermissionState {
    sessiontoken: string;
    freshtoken: string;
    roles: string[];
}

@Module({ dynamic: true, store, name: 'permission' })
class Permission extends VuexModule implements PermissionState {
    public sessiontoken: string;
    public freshtoken: string;
    public roles: string[];

    constructor(props: any) {
        super(props);
        this.sessiontoken = sessionStorage.getItem('sessiontoken') || '';
        this.freshtoken = sessionStorage.getItem('freshtoken') || '';
        this.roles = [];
        // this.routes = constantRoutes.concat(asyncRoutes);
        // this.dynamicRoutes = asyncRoutes;
    }

    @Action
    public test(roles: string[]) {
        console.log(this);
        return this.setTest(roles);
    }

    @Mutation
    private setTest(roles: string[]) {
        console.log(roles);
        this.roles = roles;
        return roles;
    }

    // @Action
    // public generateRoutes(roles: string[]) {
    //     let accessedRoutes = filterAsyncRoutes(asyncRoutes, roles);
    //     this.settingRoutes(accessedRoutes);
    // }

    // @Mutation
    // private settingRoutes(routes: RouteConfig[]) {
    //     this.routes = constantRoutes.concat(routes);
    //     this.dynamicRoutes = routes;
    // }
}

export const PermissionModule = getModule(Permission);
  • 使用方法 隨便一個 vue 檔案
<template>
    <div>
        <div>{{roles}}</div>
        <el-button @click="() => test(['1','2','3'])">Test</el-button>
    </div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import { PermissionModule } from '../store/modules/permission';
export default defineComponent({
    setup() {
        return {
            roles: computed(() => PermissionModule.roles),
            test: PermissionModule.test,
        };
    }
})
</script>
  • 模組化非同步使用 在模組中非同步 注入
  • 如 layout/store.ts
import { VuexModule, Module, Action, Mutation } from 'vue-pandora-decorators';
import store from '/@/store';

export interface LayoutState {
    testObj: {
        name: string;
        test?: { name: string; }
    };
}

@Module({ store })
export class Layout extends VuexModule implements LayoutState {
    public testObj: { name: string; };

    constructor(props: any) {
        super(props);
        this.testObj = { name: '111' };
    }

    @Action({ commit: 'testActionSuccess' })
    public testAction(obj: string[]) {
        return obj;
    }

    @Mutation
    protected testActionSuccess(obj: string[]) {
        this.testObj = { ...this.testObj, [(new Date).getTime()]: obj };
        return this.testObj;
    }
}
  • layout/layout.vue
<template>
    <div>
        <div>{{roles}}</div>
        <div>{{computed}}</div>
        <el-button @click="() => test(['1','2','3'])">Test</el-button>
    </div>
    <!-- <div>
        <div>{{testObj}}</div>
        <el-button @click="() => editObj(['1','3'])">測試 Composition API</el-button>
    </div>
    <el-button @click="() => testAction(['1','3'])">測試 Vuex 抽離的控制器層</el-button> -->
    <router-view />
</template>
<script lang="ts">
import { Component, PureComponent, state, computed } from 'vue-pandora-decorator';
import { PermissionModule } from '../store/modules/permission';
// import { Layout, LayoutState } from './store';

@Component
export default class extends PureComponent {

    @state(()=> PermissionModule.roles)
    public roles!: string[];

    @computed
    public get computed() {
        return `${(new Date).getTime()}${(this.roles || []).join('')}`;
    }

    public get test() {
        return PermissionModule.test;
    };

    constructor(props: any,ctx:any){
        super(props,ctx);
        this.roles = PermissionModule.roles;
    }
}

// export default defineComponent({
//     setup() {
//         const state = useState<LayoutState>(Layout);
//         useAction(Layout).testAction(['1','3']);

//         const actions = useActions(Layout);

//         return {
//             roles: computed(() => PermissionModule.roles),
//             ...state,
//             test: PermissionModule.test,
//             editObj: useAction(Layout).testAction,
//             ...actions,
//         };
//     }
// })
</script>
</script>

在最後感謝一下 vuex-module-decorators 的作者

  • 這裡偷懶直接使用大佬的 庫 十分感謝
  • 後續迭代更多 需要支援的 API
  • 最後再提一嘴 VUE 3.0 深入理解後確實不錯 一開始看到 這義大利麵條真心沒胃口
  • 但經過思想鬥爭後 開始 開發這個外掛 寫到後面發現 面向物件與 Composition API 可以擦出別樣的火花
  • 感謝尤大大
  • 請根據自己喜好食用 ✌️