1结构
├── index.html
├── main.js
├── api
│ └── ... # 抽取出API请求
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules
├── cart.js # 购物车模块
└── products.js # 产品模块
2使用
1安装
npm install vuex --save
2新建store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0,
total: 0
},
getters: {
isEven(state) {
return state.count % 2 === 0
}
},
mutations: {
increase(state, n) {
state.count += n
}
},
actions: {//通常是在actions内执行异步操作,同步事件可直接在mutations内执行更方便
increase({ commit }) {
commit('increase')
}
},
modules: {
//
}
})
export default store
3在根实例中注册 store 选项
在main.js:
import store from 'xxx/store/index'
new Vue({
store,
render: h => h(App)
}).$mount('#app');
通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。
3核心概念
state
一、可以从this.$store.state.xxx拿到state数据
<p>{{this.$store.state.count}}</p>
...
console.log(this.$store.state.count)
二、引入mapState辅助函数,可以接收一个对象或数组,写在computed里面
(1)接收数组
import { mapState } from 'vuex'
export default {
// ...
computed: {
...mapState(['count','total']) //直接使用count total
}
}
(2)接收对象
import { mapState } from 'vuex'
export default {
// ...
computed: {
...mapState({
count: state => state.count,
total: state => state.total
})
}
}
getters---store的计算属性
一、可以从this.$store.getters.xxx拿到state数据
this.xxx = this.$store.getters.xxx
二、引入mapGetters辅助函数,可以接收一个对象或数组,写在computed里面
(1)接收数组
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
...mapGetters(['isEven']) //可以直接使用{{isEven}}或this.isEven
}
}
(2)接收对象
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
...mapGetters({
//把 `this. myIsEven ` 映射为 `this.$store.getters. isEven`
myIsEven: 'isEven'
})
}
}
mutations---更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
一:this.$store.commit()
<h1 @click="add(1)">{{count}}</h1>
....
export default {
// ...
methods: {
add(num) {
this.$store.commit('increase', num) //第一个参数是mutations中方法,第二个参数是传递给该方法的参数
},
}
}
对象风格的提交方式
this.$store.commit({
type: 'increase',
amount: 10
})
当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此 handler 保持不变:
mutations: {
increase (state, payload) {
state.count += payload.amount
}
}
使用常量替代 Mutation 事件类型
新建store/type.js:
export const SOME_MUTATION = 'SOME_MUTATION'
在store/index.js:
import Vuex from 'vuex'
import { SOME_MUTATION } from 'xx/type.js'
const store = new Vuex.Store({
state: { ... },
mutations: {
// 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
[SOME_MUTATION] (state) {
// mutate state
}
}
})
二、引入辅助函数mapMutations,写在methods里面
<h1 @click="add(1)">{{count}}</h1>
....
export default {
// ...
methods: {
...mapMutations({
/// 将 `this. add()` 映射为 `this.$store.commit('increase')`
add: 'increase'
}),
}
}
actions---提交 mutation,可以包含任意异步操作
一、this.$store.dispatch()提交一个动作
...
this.$store.dispatch('increase') //increase是actions里的一个方法,通过increase去提交mutation
通常是在action里执行异步操作
actions: {
increaseAsync ({ commit }) {
setTimeout(() => {
commit('increase')
}, 1000)
}
}
二、引入辅助函数mapActions,写在methods里面
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions({
//// 将 `this.add()` 映射为 `this.$store.dispatch('increase')`
add: 'increase'
}),
}
}
modules---将store分割成模块,每个模块拥有自己的 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
}
})
//this.$store.state.a -> moduleA 的状态
//this.$store.state.b -> moduleB 的状态
模块的局部状态
const moduleA = {
state: { count: 0 },
mutations: {
increment (state) {
// 这里的 `state` 对象是模块的局部状态
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState:
const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
命名空间---namespaced: true
默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的,可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。设置后使用辅助函数要把第一个参数设置为对应的模块名。
const store = new Vuex.Store({
modules: {
home: {
namespaced: true,
// 模块内容(module assets)
state: { ... }, // ->this.$store.state.home.count和 ...mapState('home',['count']),
getters: {
isAdmin () { ... } // -> this.$store.getters['home/isAdmin']和...mapGetters({isAdmin: 'home/isAdmin' }),
},
actions: {
login () { ... } // -> this.$store.dispatch('home/login')
},
mutations: {
login () { ... } // -> this.$store.commit('home/login')
},
}
}
})