解释:集中响应式数据管理,一处修改多处使用,主要应用于大中型项目。
安装:
第一:index.js:(注册store仓库)
npm install vuex -D // 下载vuex
import Vue from 'vue';
import vuex from 'vuex' // 全局引入
Vue.use(vuex) // 全局注册
import actions from './actions.js';
import mutations from './mutations.js';
import getters from './getters.js';
import state from './state.js';
export default new Vuex.Store({ // 创建状态管理(大写)
actions,mutations,getters,state
}) 第二: main.js:(在根组件内挂载store)
import store from './store/index.js' // 根组件
new Vue({
el: '#app',
render: h => h(App),
router, // 路由挂载
store, // 状态管理挂载
}) 原理:
用户提交请求到Actions(如:this.$store.dispatch{type:'showNav'})===> Actions将类型和数据提交给mutations ===> mutations修改state的值 ===> 用户通过getters拿到结果。 流程:
第1步:types.js: (使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名)
export const SHOW_NAV = 'SHOW_NAV';
export const HIDE_NAV = 'HIDE_NAV';
export const SHOW_FOOT = 'SHOW_FOOT';
export const HIDE_FOOT = 'HIDE_FOOT'; 第2步: Actions:(处理逻辑,将处理的结果给mutations)
(通过commit返回给mutations,state是仓库的容器,payload是@click=" addItem(items) "传递过来的数据)
// 引入types文件,并遍历
import {SHOW_NAV,HIDE_NAV,SHOW_FOOT,HIDE_FOOT} from './types.js' // 第1种遍历的方法
import * as types from './types.js' // 第2种遍历的方法,类似遍历types文件所有的对象 export default {
showNav:({commit,state} ,payload )=>{
commit(types.SHOW_NAV)
},
hideNav:({commit,state},payload)=>{
commit(types.HIDE_NAV)
// console.log(payload) // 拿到数据
},
showFoot:({commit,state})=>{
commit(types.SHOW_FOOT)
},
hideFoot:({commit,state})=>{
commit(types.HIDE_FOOT)
},
addItem:({commit,state},payload)=>{ // 加入购物车
let find = false;
state.buycar.forEach((item,index)=>{
if(item.id == payload.id){ //有商品即数量累加
item.number++;
find = true;
}
});
commit(types.ADD_ITEM,state.buycar) // 传递载荷(参数)给mutations
}
} 第3步: mutations: (做数据突变,用action传递过来的参数,直接修改state的键值)
export default {
[types.SHOW_NAV]:(state)=>{state.bNav = true}, // state为第3步的状态对象
[types.HIDE_NAV]:(state)=>{state.bNav = false},
[types.SHOW_FOOT]:(state)=>{state.bFoot = true},
[types.HIDE_FOOT]:(state)=>{state.bFoot = false},
[types.SHOW_LOADING]:(state)=>{state.bLoading = true},
[types.HIDE_LOADING]:(state)=>{state.bLoading = false},
[types.ADD_ITEM]:(state,payload)=>{
state.buycar = payload; // payload就是action传递过来的参数
},
} 第3步: state: (接收mutations修改过后的状态)
export default {
bNav:true,
bFoot:true,
bLoading:false,
buycar:[],
} 第4步: getters: (获取state对象里面的键值)
export default {
getNav:(state)=>{return state.bNav}, // 返回state状态到vuex身上
getFoot:(state)=>{return state.bFoot},
getLoading:(state)=>{return state.bLoading},
getBuycar:(state)=>{return state.buycar},
} 第5步: 使用状态管理:
<!--使用状态管理-->
<template>
<navbar v-show="getNav"></navbar> (5)结果的使用
<span @click="addItem(items)">订阅</span> (4)通过点击事件触发actions方法(也可以通过钩子函数触发this.$store.dispatch( { type:'show_nav',payload:'2'} ))或者this.$store.dispatch('show_nav,{payload:2}')
</template> (1)解构状态管理,从vuex身上结构mapGetters、mapActions,得到getters、actions身上全部的方法集合
import { mapActions, mapGetters } from 'vuex';
export default {
methods: {
(2) mapActions接管===》方法methods // 使用延展操作,解决自定义与mapgetters的并存
...mapActions(
['addItem', 'changeItem', 'emptyItem', 'deleItem']
)
},
computed: {
(3) mapGetters接管===》计算属性computed // 使用延展操作解决自定义与mapgetters的并存
...mapGetters(
[ ' getNav ' , ' getFoot ' ,'getBuycar']
)
},
} 触发状态管理的方法:
第一种:已经解构mapActions的情况下,通过点击事件决定时机触发actions里的方法,案例如上:;
第二种:没有解构mapActions时,通过钩子函数决定时机,然后this.$store.dispatch( { type:'show_nac',payload: } )
状态管理的应用:(导航栏的显示隐藏)
在根组件下,监听路由变化,来决定是否隐藏显示
watch:{ // 状态监听
$route(to,from){
console.log(to,from) // to去向的路由 from来自哪个的路由
let path = to.path; // 拿到路由 ,如:/home
if(/user|login/){
this.$store.dispatch({type:'show_nav',payload:'xxoo'})
}
}
} 总结
Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:
应用层级的状态应该集中到单个 store 对象中。
提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
异步逻辑都应该封装到 action 里面。
只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。
对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。 组合 Action
Action 通常会异步的请求,那么如何知道 action 什么时候结束呢?更重要的是,我们如何才能组合多个 action,以处理更加复杂的异步流程?
首先,你需要明白 store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise:
(通俗的讲,如果action内执行的是ajax请求,那返回的是promise,也就是可以通过then接收)
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
} 现在你可以:
store.dispatch('actionA').then(() => {
// ...
})
在另外一个 action 中也可以:
actions: {
// ...
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
} 最后,如果我们利用 async / await,我们可以如下组合 action:
// 假设 getData() 和 getOtherData() 都是ajax请求返回的是 Promise
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
} 一个 store.dispatch 在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。