一、什么是 Vuex ?
Vuex 可以理解为一种开发模式或框架。比如 PHP 有 thinkphp, java 有 spring 等。通过状态(数据源)集中管理驱动组件的变化(好比 spring 的 IOC 容器对 bean 进行集中管理)
二、Vuex 的5个核心属性
1、state
state 为单一状态树,在 state 中需要定义我们所需要管理的数组、对象、字符串等等,只有在这里定义了,在 Vue.js 的组件中才能获取你定义的这个对象的状态。
2、getter
getter 优点类似于 Vue.js 的计算属性,当我们需要从 store 的 state 中派生出一些状态,那么我们就需要使用 getter, getter 会接收 state 作为第一个参数,而且 getter 的返回值会根据它的依赖被缓存起来,只有 getter 中的依赖值(state 中的某个需要派生状态的值)发生改变的时候才会被重新计算。
3、mutation
更改 store 中 state 状态的唯一方法就是提交 mutation ,就很类似事件。每个 mutation 都有一个字符串类型的事件类型和一个回调函数,我们需要改变 state 的值就要在回调函数中改变。我们要执行这个回调函数,那么我们需要执行一个相应的调用方法:store.commit。
4、action
action 可以提交 mutation ,在 action 中可以执行 store.commit,而且 action 可以有任何的异步操作。在页面中如果我们需要调用这个 action ,则需要执行 store.dispatch。
5、module
module 其实只是解决了当 state 中很复杂臃肿的时候,module 可以将 store 分割成模块,每个模块中拥有自己的 state、mutation、action 和 getter。
三、Vuex 的使用示例
1、Vuex 无模块化(适合小项目)
1.1、src/store/index.js
// 0.导入 Vue
import Vue from 'vue'
// 1.下包 vuex
// 2.导入 Vuex
import Vuex from 'vuex'
// 3.安装 vue 插件
Vue.use(Vuex)
// 4.创建 Store 实例对象
const store = new Vuex.Store({
// ◆state 全局共享的数据
state: {
count: 1,
price: 20
},
// ◆mutations 同步操作
mutations: {
addCount (state, payload) {
state.count += payload
}
},
// ◆actions 异步操作
actions: {
addAsync (context, payload) {
setTimeout(() => {
context.commit('addCount', payload)
}, 1000)
}
},
// ◆getters 计算属性
getters: {
totalPrice (state) {
return state.count * state.price
}
},
// ◆modules 模块化
modules: {
}
})
// 5.默认导出
export default store
1.2、main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 6.导入 store
import store from './store'
Vue.config.productionTip = false
// 7.把 store 挂载到 vue 实例上
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
1.3、页面使用
法1:直接使用 this.$store(推荐)
<template>
<div>
<!-- ◆在模板中直接使用 this.$store.state.数据 (this可以省略) -->
<p>商品价格:{{ $store.state.price }}元/件</p>
<p>购买数量:{{ $store.state.count }}件</p>
<button @click="addHandler">同步++</button>
<button @click="addAsyncHandler">异步++</button>
<!-- ◆在模板中直接使用 this.$store.getters.数据 (this可以省略) -->
<p>商品总价:{{ $store.getters.totalPrice }}元</p>
</div>
</template>
<script>
export default {
methods: {
addHandler () {
// ◆直接使用 commit 方法: this.$store.commit('函数名',载荷)
this.$store.commit('addCount', 5)
},
addAsyncHandler () {
// ◆直接使用 dispatch 方法: this.$store.dispatch('函数名',载荷)
this.$store.dispatch('addAsync', 10)
}
}
}
</script>
法2:利用辅助函数
<template>
<div>
<p>商品价格:{{ price }}元/件</p>
<p>购买数量:{{ count }}件</p>
<button @click="addHandler">同步++</button>
<button @click="addAsyncHandler">异步++</button>
<p>商品总价:{{ totalPrice }}</p>
</div>
</template>
<script>
// 按需导入辅助函数
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {
computed: {
// ◆在 computed 中映射辅助函数 ...mapState(['要映射的数据'])
...mapState(['count', 'price']),
// ◆在 computed 中映射辅助函数 ...mapGetters(['要映射的计算属性'])
...mapGetters(['totalPrice'])
},
methods: {
// ◆在 methods 中映射辅助函数 ...mapMutations(['函数名'])
...mapMutations(['addCount']),
// ◆在 methods 中映射辅助函数 ...mapActions(['函数名'])
...mapActions(['addAsync']),
addHandler () {
// 载荷只能有一个, 如果需要传递多个参数,就要用数组或对象
// 调用 addCount 函数
this.addCount(5)
},
addAsyncHandler () {
// 载荷只能有一个, 如果需要传递多个参数,就要用数组或对象
// 调用 addAsync 函数
this.addAsync(10)
}
}
}
</script>
2、vuex 有模块化(适合大项目)
2.1、src/store/modules/goods.js 子模块
// ◆默认导出子模块 user
export default {
// ◆◆◆子模块必须开启命名空间
namespaced: true,
// ◆state 全局共享的数据
state: () => ({
count: 1,
price: 20
}),
// ◆mutations 同步操作
mutations: {
addCount (state, payload) {
state.count += payload
}
},
// ◆actions 异步操作
actions: {
addAsync (context, payload) {
setTimeout(() => {
context.commit('addCount', payload)
}, 1000)
}
},
// ◆getters 计算属性
getters: {
totalPrice (state) {
return state.count * state.price
}
},
// ◆modules 模块化 (子模块也可以导入它的子模块)
modules: {
}
}
2.2、src/store/index.js
// 0.导入 Vue
import Vue from 'vue'
// 1.下包 vuex
// 2.导入 Vuex
import Vuex from 'vuex'
// ◆导入子模块 goods
import goods from './modules/goods'
// 3.安装 vue 插件
Vue.use(Vuex)
// 4.创建 Store 实例对象
const store = new Vuex.Store({
// ◆modules 模块化
modules: {
goods
}
})
// 5.默认导出
export default store
2.3、main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 6.导入 store
import store from './store'
Vue.config.productionTip = false
// 7.把 store 挂载到 vue 实例上
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
2.4、页面使用
法1:利用辅助函数(推荐)
<template>
<div>
<p>商品价格:{{price }}元/件</p>
<p>购买数量:{{count }}件</p>
<button @click="addHandler">同步++</button>
<button @click="addAsyncHandler">异步++</button>
<p>商品总价:{{ totalPrice }}元</p>
</div>
</template>
<script>
// 按需导入辅助函数
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {
computed: {
// ◆在 computed 中映射辅助函数 ...mapState('模块名',['要映射的数据'])
...mapState('goods', ['price', 'count']),
// ◆在 computed 中映射辅助函数 ...mapGetters('模块名',['要映射的计算属性'])
...mapGetters('goods', ['totalPrice'])
},
methods: {
// ◆在 methods 中映射辅助函数 ...mapMutations('模块名',['函数名'])
...mapMutations('goods', ['addCount']),
// ◆在 methods 中映射辅助函数 ...mapActions('模块名',['函数名'])
...mapActions('goods', ['addAsync']),
addHandler () {
// 调用 addCount 函数
this.addCount(5)
},
addAsyncHandler () {
// 调用 addAsync 函数
this.addAsync(10)
}
}
}
</script>
法2、直接使用 this.$store
<template>
<div>
<!-- ◆在模板中直接使用 this.$store.state.模块名.数据(this可以省略) -->
<p>商品价格:{{ $store.state.goods.price }}元/件</p>
<p>购买数量:{{ $store.state.goods.count }}件</p>
<button @click="addHandler">同步++</button>
<button @click="addAsyncHandler">异步++</button>
<!-- ◆ this.$store.getters['模块名/映射的计算属性'] -->
<p>商品总价:{{ $store.getters['goods/totalPrice']}}元</p>
</div>
</template>
<script>
export default {
methods: {
addHandler () {
// ◆直接使用 commit 方法: this.$store.commit('模块名/函数名',载荷)
this.$store.commit('goods/addCount', 5)
},
addAsyncHandler () {
// ◆直接使用 dispatch 方法: this.$store.dispatch('模块名/函数名',载荷)
this.$store.dispatch('goods/addAsync', 10)
}
}
}
</script>