1.简介
1.1Vuex是什么
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
Vuex其实是管理数据状态的一个库。通过创建一个集中的数据存储供程序中所有组件访问,
简单来说,用来集中管理数据,类似于React中的Redux,都是基于Flux的前端状态管理框架
image.png在应用 vuex 之前,我们还是需要看懂这个流程图。
① Vue Components 是我们的 vue 组件,组件会触发(dispatch)一些事件或动作,也就是图中的 Actions;
② 我们在组件中发出的动作,肯定是想获取或者改变数据的,但是在 vuex 中,数据是集中管理的,我们不能直接去更改数据,所以会把这个动作提交(Commit)到 Mutations 中;
③ 然后 Mutations 就去改变(Mutate)State 中的数据;
④ 当 State 中的数据被改变之后,就会重新渲染(Render)到 Vue Components 中去,组件展示更新后的数据,完成一个流程。
官网地址:https://vuex.vuejs.org/zh/
1.2为什么要使用Vuex?
当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
-
多个视图依赖于同一状态。
-
来自不同视图的行为需要变更同一状态。
-
对于问题一,传参的方式对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。
-
对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
什么情况下我应该使用 Vuex
- 如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。
- 如果应用够简单,最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果需要构建一个中大型单页应用,很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择
2. 基本用法
2.1 安装vuex
cnpm install vuex -S
* vue cli 3 中搭建脚手架预设时选择了“vuex”后便安装了vuex,可跳过此步阅读
2.2 创建store.js文件,在main.js中导入并配置store.选项
import store from './store' //引入文件
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
2.3 编辑store.js文件
Vuex的核心是Store(仓库),相当于是一个容器,一个store实例中包含以下属性的方法:
state 定义属性(状态、数据)
getters 用来获取属性
actions 定义方法(动作)、异步操作
commit 提交变化,修改数据的唯一方式就是显式的提交mutations,并且这个过程是同步的
mutations 修改状态
注:不能直接修改数据,必须显式提交变化,目的是为了追踪到状态的变化
store.js 中写入:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//vuex中的数据源,我们需要保存的数据就保存在这里,可以在页面通过 this.$store.state来获取我们定义的数据;
var state = {
count: 2
}
//定义getters
// Getter相当于vue中的computed计算属性,
// getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算,
// 这里我们可以通过定义vuex的Getter来获取,Getters 可以用于监听、state中的值的变化,返回计算后的结果
var getters = {
getterCount (state) {
return state.count + 1
}
}
//如果需要修改store中的值唯一的方法就是提交mutation来修改
const mutations = {
mutationsAddCount (state) {
state.count++;
},
reduction (state) {
state.count--;
}
}
//定义actions
//Action 类似于 mutation,不同在于:
// Action 提交的是 mutation,而不是直接变更状态。
// Action 可以包含任意异步操作。
const actions = {
// actionsAddCount (context) {//包含:commit、dispatch、state
// console.log(context);
// commit 提交变化,修改数据的唯一方式就是显式的提交 mutations
// context.commit('mutationsAddCount')
// },
actionsAddCount ({ commit, state }) {
// ({commit,state}) 这种写法是 es6 中的对象解构
commit('mutationsAddCount'); //提交一个名为mutationsAddCount的变化,名称可自定义,可以认为是类型名,
//和 mutations 中的 mutationsAddCount 对应
},
reduction ({ commit, state }) {
commit('reduction');
},
addAsync ({ commit, state }) {
//异步操作
var p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 3000);
});
p.then(() => {
commit('mutationsAddCount');
}).catch(() => {
console.log('异步操作');
});
}
}
export default new Vuex.Store({
state,
getters,
mutations,
actions
})
2.3.1 State:
vuex中的数据源,我们需要保存的数据就保存在这里,可以在页面通过 this.$store.state来获取我们定义的数据,我们新建一个Test.vue组件,并在Test.vue中调用它。
image.png调用:
image.png页面上:
image.png2.3.2 Getters:
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
image.png调用:
image.png页面上:
image.png2.3.3 Mutations:
数据我们在页面已经获取到了,但是如果我们需要修改count值怎么办?如果需要修改store中的值唯一的方法就是提交mutation来修改
添加mutations,在mutations中定义两个函数,用来对count加1和减1
image.pngTest.vue文件中添加两个按钮,一个加1,一个减1;这里我们点击按钮调用addFun(执行加的方法)和reductionFun(执行减法的方法),然后在里面直接提交mutations中的方法修改值:
image.png页面上点击+、- 按钮操作数据:
点击 “+”按钮
image.png再点击:
image.png2.3.4 Actions:
mutation中是存放处理数据的方法的集合,我们使用的时候需要commit。但是commit是同步函数,而且只能是同步执行。那我们想异步操作怎么办?
这个时候就需要用到actions了
在actions中提交mutation,并且可以包含任何的异步操作行。actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据(但是还是通过mutation来操作,因为只有它能操作)
image.png image.png使用dispath来触发:
image.png我们点击页面,效果是一样的。
image.png这里已经实现了一个基本的vuex修改状态值的完整流程,如果我们需要指定加减的数值,那么我们可以在dispatch中传入第二个参数,然后在actions中的对应函数中接收参数:
image.png image.png image.png
2.3.5 mapState、mapGetters、mapActions
我们在子组件中是通过“this.store.dispatch('fnName')”访问的,看起来并不是那么简洁 ,vuex官方给了我们一个更简单的方式来使用vuex, 也就是 {mapState, mapMutations, mapActions, mapGetters}
mapState 用来获取state
mapGetters 用来获取属性(数据)
mapActions 用来获取方法(动作)
在Test.vue文件中,调用代码如下:
<template>
<div>
<!-- 对应 mapState 中的count -->
<div>我是直接获取的值:{{count}}</div>
<!-- 对应 mapGetters 中的 getterCount -->
<div>我是从getters获取的计算后的值:{{getterCount}}</div>
<button @click="addFn">点击+1</button>
<button @click="reductionFn">点击-1</button>
</div>
</template>
<script>
import { mapActions, mapState, mapGetters } from 'vuex'
export default {
name: "detail",
data () {
return {}
},
components: {
},
computed: {
//在这里映射 store.state.count,使用方法和 computed 里的其他属性一样
...mapState(['count']),
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'getterCount'
])
// ...mapGetters({
// myCount: 'getterCount' // getterCount 不是字符串,对应的是getter里面的一个方法名字 然后将这个方法名字重新取一个别名 myCount
// })
},
methods: {
//在这里引入 action 里的方法,使用方法和 methods 里的其他方法一样
...mapActions([
'actionsAddCount', //该actionsAddCount来自store.js中导出的 actions 中的 actionsAddCount
'reduction'
]),
addFn () {
this.actionsAddCount()
},
reductionFn () {
this.reduction()
}
}
}
</script>
3. Vuex模块化
当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
|-store
|-index.js
|-getters.js
|-actions.js
|-mutations.js
|-modules //模块文件 分为多个模块,每个模块都可以拥有自己的state、getters、actions、mutations
|-user.js
|-cart.js
|-goods.js
|-order.js
|....
index.js中引入:
import Vue from 'vue'
import Vuex from 'vuex'
//
import user from './module/user'
import card from './module/card'
import goods from './module/goods'
import order from './module/order'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
//
},
mutations: {
//
},
actions: {
//
},
modules: {
user,
card,
goods,
order
}
})
调用:this.$store.state.user.userId
网友评论