目录
16.1 安装Vuex
模块化开发的安装方式
# npm 安装
npm install vuex@next --save
# yarn安装
yarn add vuex@next --save
16.2 基本用法
Vuex使用单一状态树,就是说,用一个对象包含了所有应用层级的状态,作为唯一的数据源而存在。每一个Vuex应用核心是store,store可以理解为保存应用程序状态的容器。store与普通的全局对象的区别有以下两点:
1. Vuex的状态存储是响应式的。当Vue组件从store中检索状态的时候,如果store中的状态发生变化,那么组件也会相应地得到高效更新。
2. 不能直接改变store中的状态。改变store中状态的唯一途径就是显示提交mutation。这可以确保每个状态更改都留下可跟踪的记录,从而能够启用一些工具来帮助我们更好地理解应用。
16.2.1 State
# store/index.js
import { createStore } from 'vuex'
const store = createStore({
// 状态通过state()函数返回
state () {
return {
count:0
}
},
})
export default store
# main.js
import { createApp } from 'vue'
import App from '/App.vue'
import store from './store'
createApp(App).use(store).mount('#app')
16.2.2 Getter
getter相当于store的计算属性,它的作用是对state的数据做一些简单的事情,例如筛选、过滤操作。假设我们需要获取正在销售的图书,因此可以定义一个getter方法,对state中的books进行过滤。代码如下:
# store/index.js
import { createStore } from 'vuex'
const store = createStore({
//
getters:{
sellingBooks: state => state.books.filter(book => book.isSold === true)
}
})
export default store
16.2.3 Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
# store/index.js
import { createStore } from 'vuex'
const store = createStore({
strict: true, // 严格模式
// mutations选项中定义修改状态的方法
// 这些方法接收state作为第1个参数
mutations:{
increment(state,n){
state.count+=n
}
}
})
export default store
更改状态的方法,需要通过mutation进行提交
store.commit('increment', 10)
16.2.4 Action
在定义mutation时,一条重要的原则是mutation必须是同步函数。换句话说,在mutation()处理器函数中,不能存在异步调用。如果需要执行异步操作,那么应该使用action。action类似于mutation,不同之处在于:
- action提交的是mutation,而不是直接变更状态
- action可以包含任意异步操作
一个简单的action如下:
# store/index.js
import { createStore } from 'vuex'
const store = createStore({
strict: true, // 严格模式
// mutations选项中定义修改状态的方法
// 这些方法接收state作为第1个参数
mutations:{
increment(state,n){
state.count+=n
}
},
actions:{
increment(context){
context.commit('increment')
}
}
})
export default store
action处理函数接收一个与store实例具有相同方法和属性的context对象,因此可以利用该对象调用commit()方法提交mutation,或者通过context.state和context.getters访问state和getter。甚至可以用context.dispatch()调用其他的actiont。
如果在action中需要多次调用increment,则可以考虑ES6中的解构语法解构代码。如下:
actions:{
increment({ commit }) {
commit('increment')
}
}
1.分发action
action 通过store.dispatch()方法触发。代码如下:
store.dispatch('increment')
action和mutation看似没什么区别,实际上它们之间最主要的是action中可以包含异步操作,例如:
actions:{
incrementAsync({ commit }) {
setTimeout(() =>{
commit('increment')
},1000)
}
}
action同样支持以载荷和对象的方式进行分发。代码如下所示:
// 载荷是一个简单的值
store.dispatch('incrementAsync',10)
// 载荷是一个对象
store.dispatch('incrementAsync',{
amount:10
})
// 直接传递一个对象进行分发
store.dispatch({
type:'incrementAsync',
amount:10
})
16.2.5 Module
Vuex使用单一状态树,应用程序的所有状态都包含在一个大的对象中,当应用变的复杂时,store对象就会变的非常臃肿。为了解决这个问题,Vuex允许将store划分为多个模块,每个模块可以包含自己的state、mutations、actions、getters及嵌套的子模块。例如:
const moduleA = {
state: () => ({}),
getters:{},
mutations:{},
actions:{}
}
const moduleB = {
state: () => ({}),
getters:{},
mutations:{},
actions:{}
}
const moduleC = {
state: () => ({}),
getters:{},
mutations:{},
actions:{}
}
const store = createStore({
modules:{
a:moduleA,
b:moduleB,
}
})
store.state.a // moduleA 的状态
store.state.b // moduleB 的状态
在一个大型项目中,如果store模块划分较多,Vuex建议项目结构按照以下形式组织:
| —— store
| —————— index.js #组装模块并导出store的地方
| —————— actions.js #根级别的actions
| —————— mutations.js #根级别的mutations
| —————— modules.js #根级别的modules
| —————— car.js #购物车模块
| —————— products.js #产品模块