什么是Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
以下是一个表示“单向数据流”理念的简单示意
注意:当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏
Vue有五个核心概念,state, getters, mutations, actions, modules。
- state => 基本数据
- getters => 从基本数据派生的数据
- mutations => 提交更改数据的方法,同步!
- actions => 像一个装饰器,包裹mutations,使之可以异步。
- modules => 模块化Vuex
什么情况下我应该使用 Vuex?
Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 [store 模式 (opens new window)]就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
官方建议在开发中大型项目的情况下考虑使用Vuex。就我个人而言,当页面的非父子组件间需要实时同步更新数据时,才使用vuex,其他情况少使用。
Vuex如何使用
请看图:
整个虚线部分就是Vuex,我们可以把它看成一个公共仓库store。store中有Actions(行为)、Mutations(变动)和State(状态)。整个的逻辑是组件通过Dispatch调用Actions中的方法,Actions通过Commit调用Mutations中的方法,Mutatisons改变State中的值。
Vuex是需要下载引入的,就不多做介绍了。
Vuex的使用
vuex中取值只有一种方法,存值有两种同步方法一种异步方法
首先在store文件夹里的index.js默认是这样的:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {},
});
第一种同步传值
- 先在state属性里定义一个类型(任意类型)
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
//定义数值类型
number: 6,
},
mutations: {},
actions: {},
modules: {},
});
- 取值在该对应页面中的计算属性(computed)中------在方法(methods)中存值
<template>
<div class="home">
//页面展示
<button @click="btn">{{ number }}</button>
</div>
</template>
<script>
//引入vuex的属性mapState
import { mapState } from "vuex";
export default {
data() {
return {};
},
computed: {
//用这样方式取值
...mapState({
//箭头函数方便简介推荐使用
number: (state) => state.number,
}),
},
methods: {
btn() {
// 同步存值第一种
//使用commit('属性名','属性值')
this.$store.commit("newNumber", 666);
},
},
};
</script>
- 存值后在store中赋值给定义的number
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
number: 6,
},
mutations: {
//传过来的属性名接收两个参数(state,val)
//val是传过来的属性值
newNumber(state, val) {
state.number = val;
},
},
actions: {},
modules: {},
});
第二种同步传值
- 同样的先在state属性里定义一个类型(任意类型)
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
//定义数值类型
number: 6,
},
mutations: {},
actions: {},
modules: {},
});
- 取值在该对应页面中的计算属性(computed)中------在方法(methods)中存值
<template>
<div class="home">
//页面展示
<button @click="btn">{{ number }}</button>
</div>
</template>
<script>
//引入vuex的属性mapState
import { mapState } from "vuex";
export default {
data() {
return {};
},
computed: {
//用这样方式取值
...mapState({
//箭头函数方便简介推荐使用
number: (state) => state.number,
}),
},
methods: {
btn() {
// 同步存值第二种
//使用dispatch('属性名','属性值')
this.$store.dispatch("setNumber",666)
},
},
};
</script>
- 存值后在store中赋值给定义的number Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过context.state 和 context.getters来获取 state 和 getters。当我们在之后介绍到[Modules]时,你就知道 context 对象为什么不是 store 实例本身了。vuex官网有详细介绍
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
number: 6,
},
mutations: {
//这步也是需要的
newNumber(state, val) {
state.number = val;
},
},
actions: {
//传过来的属性名 第一个参要用{}包裹第二个是属性值
setNumber({commit}, val) {
commit("newNumber", val)
}
},
modules: {},
});
第三种异步传值
- 同样的先在state属性里定义一个类型(任意类型)
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
//定义数值类型
number: 6,
},
mutations: {},
actions: {},
modules: {},
});
- 取值在该对应页面中的计算属性(computed)中------在方法中使用(mapActions)存值
<template>
<div class="home">
//页面展示
// 异步传值需要在事件后跟参数
<button @click="btn(666)">{{ number }}</button>
</div>
</template>
<script>
//引入vuex的属性mapState,mapActions
import { mapState,mapActions } from "vuex";
export default {
data() {
return {};
},
computed: {
//用这样方式取值
...mapState({
//箭头函数方便简介推荐使用
number: (state) => state.number,
}),
},
methods: {
...mapActions({
//事件名称:"属性名"
btn: "setNumber",
}),
},
};
</script>
- 存值后在store中赋值给定义的number
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
number: 6,
},
mutations: {
//这步也是需要的
newNumber(state, val) {
state.number = val;
},
},
actions: {
//传过来的属性名 第一个参要用{}包裹第二个是属性值
setNumber({commit}, val) {
commit("newNumber", val)
}
},
modules: {},
});
以上就是vuex的使用,第一种同步方法比较简单。第二种同步和第三种异步比较相似,store中都是一样的,只在页面中存值时不一样。
Vuex模块化使用
为什么使用模块化
模块化,就是将vuex分为不同的模块,无论从项目上还是结构上,都容易维护,我们在平时写的vuex中,都是在一个文件中,写state、getters、mutations、actions。想象一下,如果我们的项目特别大,比如淘宝那么大,那么我们vuex中要维护的内容会特别多的时候,例如“购物车”需要用到vuex,“设置”需要用到vuex,“首页”也需要用到vuex,那么如果我们都写到一个文件中,就会出现代码相当的“臃肿”。这一个store文件最后好几万行代码。还怎么维护?
模块化有很多写法,我按照我认为简单的写法来演示一下。
- 首先在store里创建一个文件夹(user)默认有一个index.js文件
把state、mutations、actions拉出去在user下的index.js里默认抛出,还要有namespace:true
export default {
state: {},
mutations: {},
actions: {},
namespaced: true,
};
- 然后在store的index.js里引入创建的模块
import Vue from "vue";
import Vuex from "vuex";
//引入user下的index.js
import user from "./user";
Vue.use(Vuex);
export default new Vuex.Store({
//在这里调用
modules: { user },
});
- 在页面里引入 取值 存值 两个方法名,存值同样有三种取值只有一种
注意的是括号里第一个属性名 需要用引入的user/***,有层级。
<template>
<div class="home">
//方法后面跟参数是第三个存值 异步
<button @click="btn(123)">{{ number }}</button>
</div>
</template>
<script>
//引入vuex的两种方法
import { mapState, mapActions } from "vuex";
export default {
data() {
return {};
},
//在计算属性里
computed: {
...mapState({
// 取值只有一种
user: (state) => state.user.num,
}),
},
//在方法里存值
methods: {
btn() {
// 存值第一种 同步
// this.$store.commit("user/setUser", 5);
// 存值第二种 同步
// this.$store.dispatch("user/setUserActions",1)
},
// 存值第三种 异步
...mapActions({
btn: "user/setUserActions",
}),
},
};
</script>
- user下的index.js里放,和之前的一样
export default {
state: {
number: 5,
},
mutations: {
setUser(state, val) {
state.number = val;
},
},
actions: {
setUserActions({ commit }, val) {
commit("setUser", val);
},
},
namespaced: true,
};
vuex的模块化使用和正常使用区别不大,着重注意存值时候的属性名需要有层级,主要是可以多个组件共享状态,更好的管理和维护。