适用场景:解决多层嵌套组件之间的通信问题,或是为了更好地管理应用中错综复杂的状态关系,一般用于中大型 web 单页应用中对应用的状态进行管理.
经典案例:购物车功能,音乐播放以及登录功能等
好比data, 定义变量的地方
Vuex 使用单一状态树,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
state: {
shopCarArr: [1, 2, 3, 4] // 用于装载购物车里的数据
}
访问: this.$store.state.shopCarArr
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
参数: state, commitObj
注意1: 在严格模式下, 不能直接让vue组件修改state里的属性值, 必须触发mutations里的方法, 来修改state里的属性值
注意2: 这里的方法, 建议由actions来触发(异步), 如果只是单一的触发(同步)可以直接利用store.commit()来提交要变更的数据
可以进行网络请求和一切的异步操作
第一个参数是 store对象
第二个参数是 dispatch 传递过来的值
Vuex 允许我们在 store 中定义“getters”(可以认为是 store 的计算属性)。就像计算属性computed一样,getters 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
参数: 有个state
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutations、actions、getters、甚至是嵌套子模块——从上至下进行同样方式的分割:
注意:
export default new Vuex.Store({
modules: {
shopModule,
userModule
}
})
== vuex的核心概念到这里已经结束了,想继续深入的同学请看下文==
vuex 的 State 在单页应用的开发中本身具有一个“数据库”的作用,可以将组件中用到的数据存储在 State 中,并在 Action 中封装数据读写的逻辑。这时候存在一个问题,一般什么样的数据会放在 State 中呢? 目前主要有两种数据会使用 vuex 进行管理:
1、组件之间全局共享的数据
2、通过后端异步请求的数据
*即把通过后端异步请求的数据都纳入 vuex 状态管理,在 Action 中封装数据的增删改查等逻辑,这样可以一定程度上对前端的逻辑代码进行分层,使组件中的代码更多地关注页面交互与数据渲染等视图层的逻辑,而异步请求与状态数据的持久化等则交由 vuex 管理。*
// Stateconst state = {
userInfo: {}
}
// Mutaionconst mutations = {
UPDATE_USER_INFO (state, payload) {
state.userInfo = payload
}
}
// Actionexport const fetchUserInfo = async ({commit}) => {
// ... 请求用户数据
// 调用 Mutaion 写入用户数据
commit('UPDATE_USER_INFO', userInfo)
}
// Component// 在组件中引入 Action
...mapAction({
fetchUserInfoAction: `fetchUserInfo`
})
// 在 method 中调用 Action
let res = self.fetchUserInfoAction()
在store/index.js中
// 管理全局状态数据
// 1. 引入Vue, 和Vuex模块
import Vue from 'vue'
import Vuex from 'vuex'
// 2. 让Vue集成Vuex中间件函数
Vue.use(Vuex);
let armsModule = { // 负责管武器
state: { // 全局变量
goodList: [
{
name: "青龙刀",
num: 0
},
{
name: "丈八蛇矛",
num: 0
},
{
name: "青釭剑",
num: 0
},
] // 全局变量里的数组
},
mutations: { // 同步...数据管家
buyArmsM (state, commitObj) { // 管家类型buyArmsM(随便定义), state(全局变量), commitObj(传入的参数)
let theIndex = commitObj['index']; // 拿到索引
state['goodList'][theIndex]['num']++; // 获取到对应的对象num++
},
sellArmsM (state, commitObj) { // 负责减去
console.log(3);
let theIndex = commitObj['index'];
if (state['goodList'][theIndex]['num'] !== 0){
state['goodList'][theIndex]['num']--;
}
}
},
actions: { // 异步管家(里面放异步操作)
buyA (store, commitObj) { // store就是this.$store
setTimeout(() => { // 异步操作
store.commit("buyArmsM", commitObj); // 调用mutations修改数据
}, 1000);
}
},
getters: { // 全局环境上的 计算属性
allNum (state) {
return state['goodList'].reduce((sum, obj) => {
return sum += obj['num'];
}, 0);
}
}
};
let smokeModule = { // 负责管烟
state: {
arr: [
{
name: "中华",
price: 45,
num: 0
},
{
name: "南京",
price: 11,
num: 0
},
{
name: "黄鹤楼",
price: 18,
num: 0
}
]
},
mutations: {
buySmokeM (state, commitObj) {
let theIndex = commitObj['index'];
state['arr'][theIndex]['num']++;
}
}
};
// 3. 暴露Vuex的Store(数据仓库)对象
export default new Vuex.Store({
modules: { // 配置多个Module对象
armsModule: armsModule,
smokeModule
}
});
在具体的逻辑页面中:
<template>
<div>
<ul>
<!-- 1. 使用Vuex的变量, 可以this.$store.state 来获取 -->
<!-- 如果分了modules, 则state下要先选择Modules的名字 -->
<li v-for="(obj, index) in this.$store.state['armsModule']['goodList']">
<span>{{obj['name']}}</span>
<span>{{obj['num']}}</span>
<button @click="buy(index)">买买买</button>
</li>
</ul>
<p>分支任务: </p>
<p v-for="(obj, ind) in this.$store.state['smokeModule']['arr']" :key="ind">
<span>{{obj['name']}}</span>
<span>{{obj['num']}}</span>
<span>小计: {{obj['price'] * obj['num']}}</span>
<button @click="btn(ind)">买烟, 成年了!</button>
</p>
</div>
</template>
<script>
export default {
name: 'Home',
methods: {
buy(ind) {
this.$store.commit("buyArmsM", {index: ind}); // commit() 用于触发mutations的函数执行
// 参数1: 要执行的类型, 参数2: 要传递的参数
},
btn (ind) {
this.$store.commit("buySmokeM", {index: ind});
}
}
}
</script>
<style scoped>
</style>
注意
如果看了以上文章,你还没有明白,来找我,捶死我!