简介
Vuex用作共享状态管理或者复杂跨组件通信(非父子组件)。共享状态管理如登录状态、用户信息、购物车等等。包含以下属性:
- State:vuex 状态管理的数据源,就是一个 json 数据。
- Getter:Getter 的作用与 filters 有一些相似,可以将 State 进行过滤后输出。
- Mutation:Mutaion 是 vuex 中改变 State 的唯一途径(严格模式下),并且只能是同步操作。
- Action:对 State 的异步操作可放在 Action 中,并通过在 Action 提交 Mutaion 变更状态。
- Module:当 Store 对象过于庞大时,可根据具体的业务需求分为多个 Module。
规则
Vuex 不限制代码结构,但是它规定了规则:
- 状态集中到单个 store 对象中。
- 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
- 异步逻辑封装到 action 中。
官方示例购物车的项目结构(大型结构)。小应用代码可以统一写在store/index.js中。
├── index.html
├── main.js
├── api
│ └── ... # 抽取出API请求
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules
├── cart.js # 购物车模块
└── products.js
/*
*store里外层的action.js/mutations.js是整体公共状态
*modules里是不同模块的状态集成,也包含了state、getters、mutations、actions
*/
使用示例
在 store/index.js 中封装 store 。state 中加共享的数据,getter 过滤数据稍后在其他页面使用,mutations 处理需要修改的情况( commit 提交)和缓存数据,actions 处理异步数据dispatch提交给 mutations ,mutations 再 commit。
//store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
islogin: 0, //登录状态 0未登录 1已登陆
userInfo: '' || JSON.parse(localStorage.getItem('userInfo'))
},
getters: {
userInfo: (state) => state.userInfo,
doneTodos: (state, getters) => {
return getters.doneTodos.length
}
},
mutations: {
//修改
setUserInfo: (state, userInfo) => {
state.userInfo = userInfo
localStorage.setItem('userInfo', JSON.stringfy(userInfo))
},
setLoginStatus:(state,islogin) => {state.islogin = islogin}
},
actions: {
changeInfo(context) {
// 可以包含异步操作
// context 是一个与 store 实例具有相同方法和属性的 context 对象
}
}
});
export default store
//main.js
import store from './store'
const user_token = ''|| localStorage.getItem('token');
if (user_token) {
// 提交修改
store.commit('setLoginStatus', '1');
}
}
//login.vue部分代码
if(res.meta.status === 200){
// 提示登录成功
this.$message({
message: res.meta.msg,
type: 'success'
});
localStorage.setItem('token',res.data.token);
// 提交修改
this.$store.commit('setUserInfo',res.data.user);
}
//user.vue
您好,{{$store.getters.userInfo.username}}
State
需要修改的状态,需要在使用状态创建计算属性,这样当state修改之后能够更新。或者getter处理获取(getter带有计算属性)。
{{username}}
//直接用$store.getters
{{$store.getters.userInfo.username}}
Getter
过滤state的数据,处理后在供其他地方应用。具有计算属性一样的特质,只有state改变才会再次触发。
Getter 方法也接受 state 和其他 getters 作为前两个参数。接受getters下其他方法过滤过的数据,再次进行处理。如下
getters: {
userInfo: (state) => state.userInfo,
weekDate: state => {
return moment(state.date).format('dddd');
},
doneTodos: (state, getters) => {
return getters.weekDate.length//接受的其他 getter
}
}
mutations
mutations里的函数有两个参数 state 和 payload 。payload 是载荷也就是提交值。
mutations: {
//修改
setLoginStatus:(state,islogin) => {state.islogin = islogin}
}
//login.vue
store.commit('setLoginStatus', '1');
Action
- Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
- actions 用 dispatch 提交。
其他地方使用actions里的方法用dispatch提交,在actions方法中commit给state。这就是它为啥自带跟store一样功能的context。
//store/index.js
actions: {
// 登录
Login({commit}, userInfo) {
return new Promise((resolve, reject) => {
login(userInfo.account, userInfo.password).then(res => {
if(res.status==200){
const tokenSuccess = aa.data.token.tokenValue
commit('SET_TOKEN', tokenSuccess )
document.cookie=`cookie地址`;
token="test"+tokenSuccess ;
//setToken("test" +token)
resolve(res.data)
}
}).catch(error => {
console.log("登录失败")
reject(error)
})
})
},
}
//**.vue
toLogin() {
this.$store.dispatch('Login',arg).then(() => {
})
}
以下是action常用场景
store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise。三种方式使用:
1.直接处理数据提交给state,在其他页面使用state。(组件共享数据)
state: {
userList: [],
},
mutations: {
// 简化mutatios的代码量
updateData(state, data) {
state[data.key] = data.value;
}
},
actions:{
getUserList: async function(contex) {
let value = await axios('you api url').then(res => res.data);
contex.commit("updateData", {
key: "userList",
value
});
}
}
2.将返回promise获取数据不提交给state,其他页面使用action。(组件共享方法)
// actions.js
getUserList: async function(contex) {
let value = await axios('you api url').then(res => res.data);
return value;
}
// ***.vue
methods:{
...mapActions(["getUserList"]),
getData(){
const userList = this.getUserList();
// 后续的处理
}
}
3.获取返回的promise不提交给state,其他页面先获取数据使用action。(组件共享方法)
// actions.js
getUserList(contex) {
return axios('you api url').then(res => res.data);
}
// ***.vue
methods:{
...mapActions(["getUserList"]),
getDataSync:async function(){
const data = await this.getUserList().then(res=>res.data);
// 后续的处理
}
}
Module
[了解更多]
(https://blog.csdn.net/AiHuanhuan110/article/details/89184259#t7)
就是分很多个modules,每个 module 包含一套state/getters/mutations/action,state状态为模块内部共享状态。使用起来就是this.$store.a.state多了一层,还是一样的方法,就是从外层逻辑上分块了而已。
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB})
mapState、mapGetters、mapMutations、mapActions
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
// ...
computed: {
localComputed () { /* ... */ },
...mapState({
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
count(state) {
return state.count + this.localCount
}
}),
...mapGetters({
getterCount(state, getters) {
return state.count + this.localCount
}
})
}
methods: {
...mapMutations({
// 如果想将一个属性另取一个名字,使用以下形式。注意这是写在对象中
add: 'increment' // 将 `this.add()` 映射为`this.$store.commit('increment')`
}),
...mapActions({
add: 'increment'
})
}
}
//都可映射为以下数组样式,使用直接this.xxx即可
methods: {
...mapActions(['increment', 'incrementBy' ]),
}