VueX
Vuex 核心概念
状态管理模式,集中式存储管理:Vuex
其实就是一个针对Vue项目设计的状态机,相当于把需要共享的变量存储在状态机中(store),然后将这个状态机挂在根组件中(绑在vue实例上)使用。
State
state
是状态在机中状态的集合,相当于对象的属性集合,用来存储状态态。
Getter
getter
属于派生状态,是store中的计算属性。getter的返回值会根据它的依赖被缓存起来,并且只用当它的依赖的state值发生改变才会被重新计算。
state :{
name:'VueX的使用:',
count:0
},
getters:{
splicing:state => {//这里的state对应着上面这个state
return state.module_one.name + state.module_one.count;
}
},
Actions
Action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。异步操作mutation
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Mutation
更改 Vuex
的 store
中的状态的唯一方法是提交 mutation
。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
state :{
name:'VueX的使用:',
count:0
},
mutations:{
increase(state){//这里的state对应着上面这个state
state.module_one.count++;
//你还可以在这里执行其他的操作改变state
},
reduce(state){
state.module_one.count--;
}
},
你不能直接调用一个 mutation handler
。这个选项更像是事件注册:“当触发一个类型为 increment
的 mutation
时,调用此函数。”要唤醒一个 mutation handler
,你需要以相应的 type
调用 store.commit
方法:
this.$store.commit('increment');
Module
由于使用单一store
,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store
对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store
分割成模块(module)
。每个模块拥有自己的 state
、mutation
、action
、getter
、甚至是嵌套子模块——从上至下进行同样方式的分割
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
Vuex的应用
业务简单的项目
使用
<template>
<div>
<div @click="clickAction('increase')">increase</div>
<div @click ="clickAction('reduce')">increase</div>
<label>{{conunt}}</label>
<label>{{splicingString}}</label>
</div>
</template>
<script>
export default {
data () {
return {
conunt:'',
splicingString:''
}
},
}
methods:{
clickAction (flag) {
if (flag == 'increase') {
// this.$store.commit('increase');
this.$store.dispatch('changeAsyn');
}else {
this.$store.commit('reduce');
}
this.conunt = this.$store.state.count;
this.splicingString = this.$store.getters.splicing;
}
}
</script>
index.js (简单的项目)
store
目录中创建index.js
文件,在此文件中创建状态机
import Vue from 'vue'
import vuex from 'vuex'
import module_one from './module-one'
Vue.use(vuex);
export default new vuex.Store({
state :{
name:'VueX的使用:',
count:0
},
mutations:{
increase(state){//这里的state对应着上面这个state
state.module_one.count++;
//你还可以在这里执行其他的操作改变state
},
reduce(state){
state.module_one.count--;
}
},
getters:{
splicing:state => {//这里的state对应着上面这个state
return state.module_one.name + state.module_one.count;
}
},
actions:{
changeAsyn(context) {
setTimeout(() => {
context.commit('increase');
}, 1000);
}
}
})
业务复杂的项目
目录结构(官方推荐)
├── index.html
├── main.js
├── components
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── state.js # 跟级别的 state
├── getters.js # 跟级别的 getter
├── mutation-types.js # 根级别的mutations名称(官方推荐mutions方法名使用大写)
├── mutations.js # 根级别的 mutation
├── actions.js # 根级别的 action
└── modules
├── m1.js # 模块1
└── m2.js # 模块2
store.js
const state = {
name:'Hello VueX',
count:0
};
export default state;
getters.js
export default {
name:state => state.name;
count:state => state.count;
splicing:state => {
return state.name + state.count;
}
}
or
export const name = (state) => {
return state.name;
}
export const count = (state) => {
return state. count
}
export const splicing = (state) => {
return `My name is ${state.name}, I am ${state.count}.`;
}
mutation-type.js
我们会将所有mutations的函数名放在这个文件里):
export const SET_NAME = 'SET_NAME';
export const SET_COUNT = 'SET_COUNT';
mutations.js
import * as types from './mutation-type.js';
export default {
[types.SET_NAME](state, name) {
state.name = name;
},
[types.SET_COUNT](state, count) {
state.count = count;
}
};
外部使用:
actions.js
// 异步操作多个commit
import * as types from './mutation-type.js';
export default {
nameAsyn({commit}, {age, name}) {
commit(types.SET_NAME, name);
commit(types.SET_COUNT, age);
}
};
modules--m1.js
export default {
state: {},
getters: {},
mutations: {},
actions: {}
};
index.js示例(组装vuex):
import vue from 'vue';
import vuex from 'vuex';
import state from './state.js';
import * as getters from './getters.js';
import mutations from './mutations.js';
import actions from './actions.js';
import m1 from './modules/m1.js';
import m2 from './modules/m2.js';
import createLogger from 'vuex/dist/logger'; // 修改日志
vue.use(vuex);
const debug = process.env.NODE_ENV !== 'production'; // 开发环境中为true,否则为false
export default new vuex.Store({
state,
getters,
mutations,
actions,
modules: {
m1,
m2
},
plugins: debug ? [createLogger()] : [] // 开发环境下显示vuex的状态修改
});
store 挂载到main.js中的vue实例上
import store from './store/index.js';
new Vue({
el: '#app',
store,
render: h => h(App)
});
or
import store from './store/index'
App.vue 文件
export default {
name: 'app',
store,//使用store
components: {
HelloWorld
}
}
mapGetters、mapActions、mapMutations
很多时候 , $store.state.dialog.name
、$store.dispatch('nameAsyn')
这种写法又长又臭 , 很不方便 , 我们没使用 vuex 的时候 , 获取一个状态只需要 this.name , 执行一个方法只需要 this. setName 就行了 , 使用 vuex 使写法变复杂了 ?
使用 mapState、mapGetters、mapActions 就是为了简化:$store.state.name
、$store.dispatch('nameAsyn')
$store.commit('SET_NAME')
、this.$store.getters.name
变成更加简单的方式:如访问 this.name
,this.splicing
,this.setName
,this.nameAsyn
。
import {mapGetters, mapMutations, mapActions} from 'vuex';
/* 只写组件中的script部分 */
export default {
computed: {
...mapGetters([
name,
age,
splicing
]),
...mapState([
'name'
])
},
methods: {
...mapMutations({
setName: 'SET_NAME',
setAge: 'SET_AGE'
}),
...mapActions([
nameAsyn
])
}
};
参考链接
Vue 官网文档
理解vuex -- vue的状态管理模式
前端框架Vue(4)——vuex 状态管理
vuex最简单、最详细的入门文档