vuex-class
bash
npm install --save vuex-class
js
import Vue from 'vue'
import Component from 'vue-class-component'
import {
State,
Getter,
Action,
Mutation,
namespace
} from 'vuex-class'
const someModule = namespace('path/to/module')
@Component
export class MyComp extends Vue {
@State('foo') stateFoo
@State(state => state.bar) stateBar
@Getter('foo') getterFoo
@Action('foo') actionFoo
@Mutation('foo') mutationFoo
@someModule.Getter('foo') moduleGetterFoo
// If the argument is omitted, use the property name
// for each state/getter/action/mutation type
@State foo
@Getter bar
@Action baz
@Mutation qux
created () {
this.stateFoo // -> store.state.foo
this.stateBar // -> store.state.bar
this.getterFoo // -> store.getters.foo
this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true })
this.mutationFoo({ value: true }) // -> store.commit('foo', { value: true })
this.moduleGetterFoo // -> store.getters['path/to/module/foo']
}
}
Vuex-Class
是一个基于decorators
(装饰器)的Vuex
状态管理库,通过利用Vue2.6的TypeScript
装饰器的特性,可以让我们在Vue
组件中更加方便地使用Vuex
。Vuex-Class
是对Vuex
库的一种补充,将Vuex
状态管理库中的API
转换成 TypeScript
的decorators
的形式。
Vuex-Class
主要特性:
- 装饰器方式 -
@State, @Getter, @Action, @Mutation
- 声明性 -
Vuex
模块化代码更易于理解和维护 TypeScript
兼容 - 可以与TypeScript
完美结合- 根据模块创建
Vuex Store
使用Vuex-Class
可以让我们在Vue
组件代码中简便地使用Vuex
状态管理库提供的一些API
,例如:
javascript
import { Component, Vue } from 'vue-property-decorator';
import { Getter, Commit } from 'vuex-class';
@Component
export default class MyComponent extends Vue {
@Getter counter!: number;
@Commit('increment') increment!: () => void;
onClick() {
this.increment();
}
}
通过上述代码,我们在MyComponent
组件中通过@Getter
装饰器来获取Vuex
状态管理库中counter
状态的值,并在onClick
方法中通过@Commit
装饰器来提交Vuex
中的increment
方法。
除此之外,Vuex-Class
还提供一些其他的装饰器和注解,如@Mutation,@Action,@Module,@Namespace
等等,它们都可以让我们更加方便地使用Vuex
。
总结而言,Vuex-Class
是一个方便使用的Vuex
状态管理库,它能够让我们在Vue
组件中更加容易地使用Vuex
的API
,强类型检查和提高代码可读性。
好的,请看下面的代码:
javascript
import { State, Getter, Action, Mutation, namespace } from "vuex-class";
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const someModule = {
namespaced: true,
state: {
count: 0
},
getters: {
doubleCount(state) {
return state.count * 2
}
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
incrementAfterDelay({ commit }) {
return new Promise(resolve => {
setTimeout(() => {
commit('increment');
resolve();
}, 1000);
});
}
}
}
const store = new Vuex.Store({
modules: {
someModule: someModule
},
state: {
name: 'Vue.js'
},
getters: {
reverseName(state) {
return state.name.split('').reverse().join('');
}
},
mutations: {
setName(state, newName) {
state.name = newName;
}
},
actions: {
setNameWithDelay({ commit }, newName) {
return new Promise(resolve => {
setTimeout(() => {
commit('setName', newName);
resolve();
}, 1000);
});
}
}
});
// 打印someModule的导出情况
console.log(someModule);
const AppComponent = Vue.extend({
template: '<div>' +
'<p>{{ name }}</p>' +
'<p>{{ reverseName }}</p>' +
'<p>{{ count }}</p>' +
'<p>{{ doubleCount }}</p>' +
'<button @click="setName">Set Name</button>' +
'<button @click="increment">Increment</button>' +
'<button @click="incrementAfterDelay">Increment after delay</button>' +
'</div>',
computed: {
// 使用 State 辅助类将 name 属性与 Vuex 中的 state.name 进行绑定
@State('name') name,
// 使用 Getter 辅助类将 reverseName 属性与 Vuex 中的 getters.reverseName 进行绑定
@Getter('reverseName') reverseName,
// 使用 namespace 函数指定 someModule,然后使用 State 辅助类将 count 属性与 someModule 中的 state.count 进行绑定
@State(state => state.someModule.count) count,
// 使用 namespace 函数指定 someModule,然后使用 Getter 辅助类将 doubleCount 计算属性与 someModule 中的 getters.doubleCount 进行绑定
@Getter(state => `someModule/${state.doubleCount}`) doubleCount
},
methods: {
// 使用 Mutation 装饰器指定 setNameWithDelay 方法调用 Vuex 中的 mutation:setName
@Mutation('setName') setName,
// 使用 Mutation 装饰器指定 increment 方法调用 Vuex 中的 mutation:increment
@Mutation(state => `someModule/${state.increment}`) increment,
// 使用 Action 装饰器指定 incrementAfterDelay 方法调用 Vuex 中的 action:incrementAfterDelay
@Action('someModule/incrementAfterDelay') incrementAfterDelay
}
});
const app = new AppComponent({
el: '#app',
store
});
在上面的代码中,我们首先定义了一个名为 someModule
的 Vuex 模块,其中包含了一个单独的状态 count
,以及计算属性 doubleCount
、变化方法 increment
和异步操作 incrementAfterDelay
。接着,我们注册了这个模块到了 Vuex 的仓库中。
然后,我们在组件中使用了 @State
、@Getter
、@Action
和 @Mutation
装饰器,分别将四个调用 Vuex 中对应对象的方法 name
、reverseName
、count
、doubleCount
、setName
、increment
和 incrementAfterDelay
绑定到了组件中的相应属性和方法上。在这些装饰器中,我们有时使用了 namespace
函数,指定了操作的模块。
最后,我们创建了一个 AppComponent
组件,并在其中使用了上述这些绑定的属性和方法。这样,在应用中我们就可以直接使用这些属性和方法,而无需手动访问 Vuex
对象了。
vue-class-component
js
<template>
<OtherComponent />
</template>
import Vue from 'vue'
import Component from 'vue-class-component'
import OtherComponent from './OtherComponent.vue'
// 如果没有OtherComponent,可以写 `@Component`
@Component({
components: {
OtherComponent
}
})
export default class HelloWorld extends Vue {
message1 = 'Hello World!' // data的响应式数据message1
message2 = undefined // 这样声明的,不是响应式的
// Declared as component method
hello() {
console.log('Hello World!')
}
// Declared as computed property getter
get name() {
return this.firstName + ' ' + this.lastName
}
// Declared as computed property setter
set name(value) {
const splitted = value.split(' ')
this.firstName = splitted[0]
this.lastName = splitted[1] || ''
}
data() {
return {
message: undefined
}
}
// Declare mounted lifecycle hook
mounted() {
console.log('mounted')
}
// Declare render function
render() {
return <div>Hello World!</div>
}
}
文件class-component-hooks.js
js
import Component from 'vue-class-component'
// 注册钩子函数
Component.registerHooks([
'beforeRouteEnter',
'beforeRouteLeave',
'beforeRouteUpdate'
])
文件main.js
js
// Make sure to register before importing any components
import './class-component-hooks' // 引入声明的钩子
import Vue from 'vue'
import App from './App'
new Vue({
el: '#app',
render: h => h(App)
})
注册钩子后,类组件将它们实现为类原型方法:
js
import Vue from 'vue'
import Component from 'vue-class-component'
@Component
export default class HelloWorld extends Vue {
// 本来是不允许这样的,但是上面已经注册过了,就可以用了
beforeRouteEnter(to, from, next) {
console.log('beforeRouteEnter')
next()
}
beforeRouteUpdate(to, from, next) {
console.log('beforeRouteUpdate')
next()
}
beforeRouteLeave(to, from, next) {
console.log('beforeRouteLeave')
next()
}
}
自定义装饰器
文件decorators.js
js
import { createDecorator } from 'vue-class-component'
export const Log = createDecorator((options, key) => {
const originalMethod = options.methods[key]
options.methods[key] = function wrapperMethod(...args) {
console.log(`Invoked: ${key}(`, ...args, ')')
originalMethod.apply(this, args)
}
})
js
import Vue from 'vue'
import Component from 'vue-class-component'
import { Log } from './decorators'
@Component
class MyComp extends Vue {
@Log
hello(value) {}
}
Extend 和 Mixins
您可以将现有类组件扩展为本机类继承。假设您有以下超类组件:
文件super.js
js
import Vue from 'vue'
import Component from 'vue-class-component'
@Component
export default class Super extends Vue {
superValue = 'Hello'
}
每个超类都必须是一个类组件。它需要继承构造函数作为祖先,并由装饰器进行装饰
js
import Super from './super'
import Component from 'vue-class-component'
@Component
export default class HelloWorld extends Super {
created() {
console.log(this.superValue) // -> Hello
}
}
文件mixins.js
js
import Vue from 'vue'
import Component from 'vue-class-component'
// You can declare mixins as the same style as components.
@Component
export class Hello extends Vue {
hello = 'Hello'
}
@Component
export class World extends Vue {
world = 'World'
}
在类样式组件中使用它们:
js
import Component, { mixins } from 'vue-class-component'
import { Hello, World } from './mixins'
@Component
export class HelloWorld extends mixins(Hello, World) {
created () {
console.log(this.hello + ' ' + this.world + '!')
// -> Hello World!
}
}
与超类一样,所有 mixin
都必须声明为类组件。
Props Definition
Vue Class Component
没有提供专门的 props
定义 API
。但是,您可以使用规范 API
来做到这一点:Vue.extend
js
<template>
<div>{{ message }}</div>
</template>
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
const GreetingProps = Vue.extend({
props: {
name: String
}
})
@Component
export default class Greeting extends GreetingProps {
get message(): string {
return 'Hello, ' + this.name
}
}
</script>
根据定义的 prop
类型的推断,可以通过扩展类组件来使用它们。Vue.extend
如果你有一个超类组件或 mixin
要扩展,请使用 helper
将定义的 props
与它们组合在一起:mixins
js
<template>
<div>{{ message }}</div>
</template>
<script lang="ts">
import Vue from 'vue'
import Component, { mixins } from 'vue-class-component'
import Super from './super'
const GreetingProps = Vue.extend({
props: {
name: String
}
})
@Component
export default class Greeting extends mixins(GreetingProps, Super) {
get message(): string {
return 'Hello, ' + this.name
}
}
</script>
vue-property-decorator
vue-property-decorator
是一个vue组件的装饰器库,它提供了一些装饰器来简化在Vue组件中使用的一些常见选项,如状态、计算属性、事件、方法等。使用它,你可以编写更加简洁、易读、易维护的Vue代码。
下面是vue-property-decorator
中一些常用的装饰器:
@Component
@Component
是在一个类组件中使用的装饰器,可以用来声明一个Vue组件并指定其模板、样式和其他与Vue组件相关的选项。
javascript
import { Component, Vue } from 'vue-property-decorator';
@Component({
name: 'my-component',
template: '<div>Hello, {{name}}!</div>',
style: `
div {
color: red;
}
`
})
export default class MyComponent extends Vue {
name = 'World';
}
@Prop
@Prop
是一个装饰器,用于声明一个组件的属性,并指定其类型、默认值和其他选项。如果要在父组件中向子组件传递数据,则需要使用该装饰器来声明子组件的props。
javascript
import { Component, Vue, Prop } from 'vue-property-decorator';
@Component
export default class MyComponent extends Vue {
@Prop(String) readonly name!: string;
@Prop({ default: 18 }) readonly age!: number;
}
@Watch
@Watch
是一个装饰器,用于监听某个属性的变化,并在其变化时执行回调。如果要在某个属性变化时执行一些操作,如调用API获取新数据、更新相关状态等,则可使用该装饰器。
javascript
import { Component, Vue, Watch } from 'vue-property-decorator';
@Component
export default class MyComponent extends Vue {
@Prop(String) readonly name!: string;
@Prop({ default: 18 }) readonly age!: number;
@Watch('name')
onNameChanged(newVal: string, oldVal: string) {
console.log(`Name changed from ${oldVal} to ${newVal}`);
}
}
@Emit
@Emit
是一个装饰器,用于在一个组件中定义一个方法,并在该方法触发时发出一个自定义事件。如果您需要在子组件中触发父组件中的事件,则可以使用该装饰器。
javascript
import { Component, Vue, Emit } from 'vue-property-decorator';
@Component
export default class MyComponent extends Vue {
counter = 0;
@Emit()
increment() {
this.counter += 1;
}
}
@Inject
@Inject
用于从父组件中注入一个属性的值。如果您需要向子组件中提供所需的实例,可以使用该装饰器。
javascript
import { Component, Vue, Inject } from 'vue-property-decorator';
@Component
export default class MyComponent extends Vue {
@Inject('theme') readonly theme!: string;
}
以上是vue-property-decorator
的一些常见装饰器及其用法。此外,该库还提供了许多其他有用的功能,如只读属性、方法修饰符等。
需要注意的是,使用vue-property-decorator
之前需要先确保您的项目中已经安装并正确配置了TypeScript
和Babel
。
详细介绍import { State, Getter, Action, Mutation, namespace } from "vuex-class"
State
State
是一个装饰器函数,用于在 Vue
组件中获取 Vuex store
中的状态(state
)。通过在类的属性上使用@State
装饰器,可以在组件中访问和使用这些状态。
javascript
import { Component, Vue } from 'vue-property-decorator';
import { State } from 'vuex-class';
@Component
export default class MyComponent extends Vue {
@State counter: number;
}
Getter
Getter
是一个装饰器函数,用于在 Vue
组件中获取 Vuex store
中的计算属性(getter
)。通过在类的属性上使用@Getter
装饰器,可以在组件中访问和使用这些计算属性。
javascript
import { Component, Vue } from 'vue-property-decorator';
import { Getter } from 'vuex-class';
@Component
export default class MyComponent extends Vue {
@Getter fullName: string;
}
Action
Action
是一个装饰器函数,用于在 Vue
组件中调用 Vuex store
中的方法(action
)。通过在类的方法上使用@Action
装饰器,可以在组件中调用这些方法。
javascript
import { Component, Vue } from 'vue-property-decorator';
import { Action } from 'vuex-class';
@Component
export default class MyComponent extends Vue {
@Action fetchData(): Promise<void> {
// 调用 Vuex store 中的 fetchData action
return this.$store.dispatch('fetchData');
}
}
Mutation
Mutation
是一个装饰器函数,用于在 Vue
组件中调用 Vuex store
中的方法(mutation
)。通过在类的方法上使用@Mutation
装饰器,可以在组件中调用这些方法。
javascript
import { Component, Vue } from 'vue-property-decorator';
import { Mutation } from 'vuex-class';
@Component
export default class MyComponent extends Vue {
@Mutation increment(): void {
// 调用 Vuex store 中的 increment mutation
this.$store.commit('increment');
}
}
namespace
namespace
是一个函数,用于在 Vuex store
中定义和管理命名空间(namespace
)。命名空间可以帮助我们更好地组织和管理 Vuex store
中的模块状态(state
)、计算属性(getters
)、方法(actions
)和提交(mutations
)。
在使用命名空间之前,我们需要在 Vuex store 的模块中指定命名空间:
javascript
// Vuex store 模块中
const exampleModule = {
namespaced: true, // 启用命名空间
state: { ... },
getters: { ... },
actions: { ... },
mutations: { ... }
};
使用namespace
函数,我们可以在 Vue
组件中直接访问和使用命名空间中的状态、计算属性、方法和提交,而不再需要手动硬编码命名空间。
javascript
import { Component, Vue } from 'vue-property-decorator';
import { namespace } from 'vuex-class';
const exampleNamespace = namespace('exampleModule');
@Component
export default class MyComponent extends Vue {
@exampleNamespace.State counter: number;
@exampleNamespace.Getter fullName: string;
@exampleNamespace.Action fetchData(): Promise<void> {
return this.exampleNamespace.dispatch('fetchData');
}
@exampleNamespace.Mutation increment(): void {
this.exampleNamespace.commit('increment');
}
}
使用namespace
函数创建了一个命名空间的装饰器对象exampleNamespace
。通过在组件的类属性上使用这些装饰器,我们可以在组件中访问和使用命名空间中的状态counter
、计算属性fullName
、方法fetchData
和提交increment
。
这种方式可以帮助我们更好地组织和封装 Vuex store
的模块,减少了在组件中硬编码命名空间的问题,并提高了代码的可读性和可维护性。需要注意的是,在使用命名空间之前,需要正确配置和安装 Vuex 和 "vuex-class"
库。
{
"name": "pawm-pms",
"version": "1.0.0",
"private": true,
"scripts": {
"serve": "hui dev",
"build": "hui build --filename-hashing",
"eslint": "npm run eslint"
},
"dependencies": {
"@pa/pawm-portal-sdk": "1.1.30",
"@fc/regex": "git+ssh://git@gitlab.pab.com.cn:LCKJ/PAWM/PAWM-FRONT/PAWM-PMS-FRONTEND-UI.git#regex",
"@fc/request": "git+ssh://git@gitlab.pab.com.cn:LCKJ/PAWM/PAWM-FRONT/PAWM-PMS-FRONTEND-UI.git#request",
"@fc/ui": "git+ssh://git@gitlab.pab.com.cn:LCKJ/PAWM/PAWM-FRONT/PAWM-PMS-FRONTEND-UI.git#ui",
"@hui/cli": "git+ssh://git@gitlab.pab.com.cn:LCKJ/PAWM/PAWM-FRONT/PACKAGE/PAWM-PMS-FRONTEND-HUI-CLI.git",
"@hui/bundler": "git+ssh://git@gitlab.pab.com.cn:LCKJ/PAWM/PAWM-FRONT/PACKAGE/PAWM-PMS-FRONTEND-HUI-BUNDLER.git#release",
"@wchbrad/vue-easy-tree": "1.0.12",
"axios": "0.21.4",
"bignumber.js": "9.1.1",
"dayjs": "1.11.7",
"devextreme": "23.1.5",
"dragselect": "2.5.5",
"echarts": "5.4.0",
"element-ui": "2.15.12",
"html2canvas": "1.0.0",
"hui-core": "git+ssh://git@gitlab.pab.com.cn:LCKJ/PAWM/PAWM-FRONT/PACKAGE/PAWM-PMS-FRONTEND-HUI-CORE.git",
"moment": "2.29.4",
"monaco-editor": "0.20.0",
"sortablejs": "1.15.0",
"vue": "2.6.10",
"vue-class-component": "7.2.6",
"vue-json-views": "1.3.0",
"vue-property-decorator": "9.1.2",
"vuex-class": "0.3.2"
},
"devDependencies": {
"@babel/core": "7.21.5",
"@babel/plugin-syntax-jsx": "7.18.6",
"@babel/plugin-transform-typescript": "7.20.2",
"@babel/preset-env": "7.20.2",
"@vue/babel-helper-vue-jsx-merge-props": "1.4.0",
"@vue/cli-plugin-babel": "5.0.8",
"ag-grid-community": "30.0.3",
"ag-grid-vue": "30.0.3",
"babel-plugin-import": "1.13.5",
"core-js": "3.26.1",
"tslib": "2.4.1",
"typescript": "4.9.3",
"typescript-plugin-css-modules": "3.4.0",
"xlsx": "0.18.5",
"xml2js": "0.6.0"
}
}