vue-class-state
TypeScript icon, indicating that this package has built-in type declarations

0.4.1 • Public • Published

vue-class-state

Vue状态管理,灵感来自mobx

vue-class-state提供以下功能:

1.stategettersmutation,其概念与vuex基本相通,区别是vue-class-state是以class(类)和decorator(装饰器)的形式来实现的。

2.简单的依赖注入,用于解决子模块之间共享数据的问题,也可与Vue的provide/inject配合使用。

3.支持严格模式,开启后state只能在mutation中被修改,支持拦截mutation。

4.支持vue官方devtool,可以在devtool的vuex标签下查看stategettersmutation

安装

npm install vue vue-class-state --save

注意:

1.TypeScript用户需要开启tsconfig.json中的experimentalDecoratorsallowSyntheticDefaultImports的编译选项

2.javaScript+Babel用户需要babel-plugin-transform-decorators-legacybabel-plugin-transform-class-properties插件。

基本使用

// store.ts

import { bind, Container, Getter, Inject, State } from 'vue-class-state';

// 定义注入标识
export const StateKeys = {
    A: 'stateA',
    B: 'stateB',
    STORE: 'store'
};

export class StateA {
    // 定义响应式数据
    @State text = 'A';
}

export class StateB {
    @State text = 'B';
}

export class Store {

    // 根据注入标识在将实例注入到类实例属性中
    // 并且在第一次读取该属性时才进行初始化
    // @Inject(StateKeys.A)  stateA!: StateA

    constructor(
        // 根据注入标识在将实例注入到构造器参数中
        @Inject(StateKeys.A) public stateA: StateA,
        @Inject(StateKeys.B) public stateB: StateB
    ) {
    }

    // 定义计算属性,
    // 并且在第一次读取该属性时才进行该计算属性的初始化
    @Getter get text() {
        return this.stateA.text + this.stateB.text;
    }

}

// 定义容器
@Container({
    providers: [
        // 绑定注入规则,一个标识对应一个类实例(容器范围内单例注入)
        bind<StateA>(StateKeys.A).toClass(StateA),
        bind<StateB>(StateKeys.B).toClass(StateB),
        bind<Store>(StateKeys.STORE).toClass(Store)
    ],
    // 开启严格模式
    strict: true
})
export class AppContainer { }
// app.ts

import Vue from 'vue';
import Component from 'vue-class-component';
import { Inject } from 'vue-class-state';
import { AppContainer, StateKeys, Store } from './store';

// 推荐使用vue官方的vue-class-component库
@Component({
    template: '<div>{{store.text}}</div>'
})
class App extends Vue {

    // 根据注入标识在子组件中注入实例
    @Inject(StateKeys.STORE) store!: Store;

}

new Vue({
    el: '#app',
    // 在根组件实例化一个容器,传入到provide选项
    provide: new AppContainer(),
    render: (h) => h(App)
});

注册类

bind<IModule>(moduleKeys.A).toClass(ModuleA)

注册值

bind<IModule>(moduleKeys.A).toValue(new ModuleA())

注册工厂

bind<IModule>(moduleKeys.A).toFactory(() => new ModuleA())

// 传入的第二个参数类型为注入标识数组,表明该工厂依赖的其他模块,会依次注入到工厂参数中
bind<IModule>(moduleKeys.B).toFactory((moduleA: IModule, moduleB: IModule) => {
    return new ModuleC(moduleA, moduleB)
}, [moduleKeys.A, moduleKeys.B])


bind<IModule>(moduleKeys.B).toFactory((moduleA: IModule, moduleB: IModule) => {
    if (isSSR) {
        return moduleA
    } else {
        return moduleB
    }
}, [moduleKeys.A, moduleKeys.B])

拦截mutation

以下是简单的缓存例子

import Vue from 'vue';
import { bind, Container, IMutation, Mutation, State } from 'vue-class-state';

// 如果想拦截某些Mutation的执行,可以创建一个新的装饰器,执行顺序和 koa(直接抄它的)一样,洋葱模型,但不支持异步
const CacheMutation = Mutation.create((next: () => void, mutation: IMutation, state: Counter) => {
    // mutation 执行前打印相关信息
    console.log(`
        mutation类型,供devtool使用: ${mutation.type}
        传入mutation方法的参数数组: ${JSON.stringify(mutation.payload)}
        调用的模块注入标识: ${mutation.identifier}
        调用的方法名: ${mutation.mutationType}
    `);
    const res = next();
    // mutation 执行后保存缓存
    localStorage.setItem(state.cacheKey, JSON.stringify(state));
    return res;
});

class Counter {

    cacheKey = 'cache-key';

    @State public num = 0;

    // 严格模式下,修改实例的state值必须调用该实例的Mutation方法
    // 和vuex一致,必须为同步函数
    @CacheMutation
    public add() {
        this.num++;
    }

    // 默认的Mutation不会被拦截
    @Mutation
    public add2() {
        this.num++;
    }

    constructor() {
        const cacheStr = localStorage.getItem(this.cacheKey);
        if (cacheStr) {
            const cache = JSON.parse(cacheStr);
            State.replaceState(this, cache);
        }
        setInterval(() => {
            // 等同于 CacheMutation.commit(this, () => this.num++, 'add');
            // 最简化写法 CacheMutation.commit(() => this.num++) ,注意由于没有传入this,这种写法中间件是拿不到state的,看情况使用
            this.add();
        }, 1000);
    }
}

const COUNTER = 'counter';

@Container({
    providers: [bind<Counter>(COUNTER).toClass(Counter)],
    strict: [COUNTER]
})
class AppContainer { }

const container = new AppContainer();

new Vue({
    el: '#app',
    template: `<div>{{counter.num}}</div>`,
    computed: {
        counter() {
            return container[COUNTER];
        }
    }
});

Readme

Keywords

Package Sidebar

Install

npm i vue-class-state

Weekly Downloads

9

Version

0.4.1

License

MIT

Unpacked Size

68 kB

Total Files

25

Last publish

Collaborators

  • zetaplus006