Vue 状态管理 Vuex
Vue 状态管理 Vuex
官网文档:https://vuex.vuejs.org/zh/
Vuex 是一个专门为 Vue.js 应用程序开发的状态管理模式,他采用集中式存储管理应用的所有组件的状态,并且以相应的规则保证状态以一种可以预测的方式发生改变。
Vuex 的简单理解
- Vue 应用中的每一个组件在 data() 中封装自己的数据属性,而这些 data 属性是私有的,完全隔离的。
- 如果我们希望多个组件都能读取到同一个状态数据属性,或者不同的组件的行为需要更新同一状态数据属性,这就需要一个将共享的状态数据属性进行集中式的管理。
- 这就是 Vuex 状态管理所要解决的问题。
安装依赖
npm install --save vuex
使用Vuex
创建文件
在项目 src 文件夹下创建一个 store 文件夹,存储状态,将所有的状态存储到这个文件夹里面。在 store 文件夹下创建一个 index.js 文件。
创建Vuex对象
在 index.js 文件中编写 Vuex 对象并导出。
在状态中存储一个 count 值为 1。
// 引入 vue 和 vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 引入 Vuex 插件
Vue.use(Vuex)
// 创建一个仓库,用来存储对应的状态
const store = new Vuex.Store({
state: { // 存放状态(共享的属性)
count: 1
}
})
// 导出Vuex对象
export default store
将 Vuex 注册到 vue实例当中
在 main.js 文件中注册 Vuex。
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
// 导入 vuex,默认导入的是 ./store/index.js
import store from './store'
Vue.config.productionTip = false;
new Vue({
router,
store, // 注册
render: h => h(App)
}).$mount("#app");
获取状态 count 值
获取状态值得方式是 $store.state.状态名。
$store.state.xxx
在组件中使用:
<template>
<div class="home">
count:{{ $store.state.count }}
</div>
</template>
<script>
export default {
name: "Home",
};
</script>
更改状态值
- 在 store 的 mutations 选项中定义方法,才可以改变状态值。
- 在通过 $store.commit("mutationName") 触发状态值的改变。
创建一个修改 count 值得方法,在 index.js 文件中,添加一个增加的方法,修改 state 对象中的 count 值。
mutations: {
// 增加的方法,改变state的状态值
increment(state) {
state.count ++
}
}
在组件中创建一个按钮,点击按钮,是的状态值 count 自增。
<template>
<div class="home">
<p>count:{{ $store.state.count }}</p>
<button @click="addCount">count 自加</button>
</div>
</template>
<script>
export default {
name: "Home",
methods: {
addCount() {
// 现获取状态值
console.log(this.$store.state.count);
// 修改 count 值
this.$store.commit('increment')
}
}
};
</script>
改变状态值 count 的方法就实现了。
在写一个自减哈,闲着也是闲着,做法和自加是一样的
index.js文件中:
mutations: {
// 增加的方法,改变state的状态值
increment(state) {
state.count ++
},
// 自减
decrement(state) {
state.count --
}
}
组件:
<template>
<div class="home">
<p>count:{{ $store.state.count }}</p>
<button @click="addCount">count 自加</button>
<button @click="decrement">count 自减</button>
</div>
</template>
<script>
export default {
name: "Home",
methods: {
addCount() {
// 现获取状态值
console.log(this.$store.state.count);
// 修改 count 值
this.$store.commit('increment')
},
decrement() {
// 现获取状态值
console.log(this.$store.state.count);
// 修改 count 值
this.$store.commit('decrement')
}
}
};
</script>
任意组件,都可以获取到状态值,数据是共享的,当一个地方改变了状态的值,所有的地方都可以获取到最新状态值。
提交载荷
就是向 $store.commit 中提交额外的参数,即 mutation 的载荷 (payload)。
例如:修改自加功能,增加的时候传进一个参数 n,是 count 加上传进来的 n。修改 index.js 文件自加方法:
mutations: {
// 增加的方法,改变state的状态值
increment(state, n) { // n 为载荷
state.count += n // state.count = state.count + n
},
// 自减
decrement(state) {
state.count --
}
}
修改组件方法:
addCount() {
// 现获取状态值
console.log(this.$store.state.count);
// 修改 count 值
// this.$store.commit('increment')
this.$store.commit('increment', 10)
},
Action的作用和使用
Action 类似于 mutation,但不同点在于:
- Action 提交的是 mutation,而不是在组件中直接变更状态,通过他间接更新 state。
- 在组件中通过 this.$store.dispatch('actionName') 触发状态值间的改变。
- Action 也支持载荷。
- Action 可以包含任意异步操作。
修改 index.js 文件,添加 actions 。
// 引入 vue 和 vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 引入 Vuex 插件
Vue.use(Vuex)
// 创建一个仓库,用来存储对应的状态
const store = new Vuex.Store({
state: { // 存放状态(共享的属性)
count: 1
},
mutations: {
// 增加的方法,改变state的状态值
increment(state, n) { // n 为载荷
state.count += n // state.count = state.count + n
},
// 自减
decrement(state) {
state.count--
}
},
actions: {
add(context) {
// 触发 mutations 中的 increment 来改变 state
context.commit('increment', 10)
}
}
})
// 导出Vuex对象
export default store
修改组件,点击自加按钮时候的逻辑:
addCount() {
// 现获取状态值
console.log(this.$store.state.count);
// 修改 count 值
// this.$store.commit('increment')
// this.$store.commit('increment', 10)
// 触发 action 修改 state
this.$store.dispatch('add')
},
action 也可以实现载荷。
actions: {
add(context, n) {
// 触发 mutations 中的 increment 来改变 state
context.commit('increment', n)
}
}
addCount() {
// 现获取状态值
console.log(this.$store.state.count);
// 修改 count 值
// this.$store.commit('increment')
// this.$store.commit('increment', 10)
// 触发 action 修改 state
this.$store.dispatch('add', 10)
},
效果一样!
action 还有其他的提交方式
比如修改减法
actions: {
add(context, n) {
// 触发 mutations 中的 increment 来改变 state
context.commit('increment', n)
},
// 参数是一个对象,commit就是提交,state就是状态对象,按需传入
decrement({commit,state}) {
console.log('actions.decrement.state.count ',state.count)
commit('decrement')
}
}
组件调用减法:
decrement() {
// 现获取状态值
// console.log(this.$store.state.count);
// 修改 count 值
// this.$store.commit('decrement')
this.$store.dispatch('decrement')
}
派生属性 getter
- 有时候哈,我们需要从 store 中的 state 中派生出一些状态。就比如说哈,基于上面的那个代码,增加一个 desc 属性,当那个 count 小于50的时候,desc 的值就是“吃饭饭”,大于等于50小于100,desc 的值就是 “睡觉觉”,当 count 的值大于100,desc 的值就是“打豆豆”。这个时候,我们就需要使用 getter 为我们解决问题了。
- getter 其实就是一个类似于计算属性(get)的对象。
- 组件中读取 $store.getter.xxx
修改 index.js 文件,增加 getters 选项:
getters: { // 定义派生属性
desc(state) { // 类似于计算属性的个玩意儿,会监听count值
// 这个state就是上面的state,他会自动的传进来
if(state.count < 50){
return '吃饭'
} else if (state.count < 100){
return '睡觉'
} else {
return '打豆豆'
}
}
}
修改组件,测试派生desc
<p>派生属性 desc 测试:{{ $store.getters.desc }}</p>
效果就是下面的样子啦:
Vuex 模块化 Module 管理
随着状态值得增加,对状态值操作的增加,index.js 文件会变得越来约大,越来越臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module),每个模块有自己的 state、mutation、action、getter 等。
结构大体就是下面的样子:
const moduleA = {
state: {},
mutations: {},
actions: {},
getters: {}
}
const moduleB = {
state: {},
mutations: {},
actions: {}
}
const store = new Vuex.Store({
modules:{
a:modeuleA,
b:modulesB
}
})
store.state.a // modelA 的状态
store.state.b // modelB 的状态
模块化之前代码
index.js 文件
// 引入 vue 和 vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 引入 Vuex 插件
Vue.use(Vuex)
// 将 home 相关的状态抽取为一个模块
const home = {
state: { // 存放状态(共享的属性)
count: 1
},
mutations: {
// 增加的方法,改变state的状态值
increment(state, n) { // n 为载荷
state.count += n // state.count = state.count + n
},
// 自减
decrement(state) {
state.count--
}
},
actions: {
add(context, n) {
// 触发 mutations 中的 increment 来改变 state
context.commit('increment', n)
},
// 参数是一个对象,commit就是提交,state就是状态对象
decrement({commit,state}) {
console.log('actions.decrement.state.count ',state.count)
commit('decrement')
}
},
getters: { // 定义派生属性
desc(state) { // 类似于计算属性的个玩意儿,会监听count值
// 这个state就是上面的state,他会自动的传进来
if(state.count < 50){
return '吃饭'
} else if (state.count < 100){
return '睡觉'
} else {
return '打豆豆'
}
}
}
}
// 将 goods 相关的状态抽取为一个模块
const goods = {
state: {},
mutations: {},
actions: {},
getters: {}
}
// 创建一个仓库,用来存储对应的状态
const store = new Vuex.Store({
modules: {
home, // home: home
goods,
}
})
// 导出Vuex对象
export default store
组件代码
<template>
<div class="home">
<!-- <p>count:{{ $store.state.count }}</p> --> <!-- 模块话之前 -->
<p>count:{{ $store.state.home.count }}</p> <!-- 模块话之后 -->
<button @click="addCount">count 自加</button>
<button @click="decrement">count 自减</button>
<p>派生属性 desc 测试:{{ $store.getters.desc }}</p>
</div>
</template>
<script>
export default {
name: "Home",
methods: {
addCount() {
// 现获取状态值
// console.log(this.$store.state.count); // 模块化钱前
console.log(this.$store.state.home.count); // 模块化后
// 修改 count 值
// this.$store.commit('increment')
// this.$store.commit('increment', 10)
// 触发 action 修改 state
this.$store.dispatch('add', 10)
},
decrement() {
// 现获取状态值
// console.log(this.$store.state.count);
// 修改 count 值
// this.$store.commit('decrement')
this.$store.dispatch('decrement')
}
}
};
</script>
一样的效果!完美~!
基于 Vuex 标准项目结构重构项目
如果所有的状态都写在一个 js 中,这个 js 必定会很臃肿,Vuex 并不限制你的代码结构。所以最好把每一部分都单独抽成一个 js 文件。
Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:
-
应用层级的状态应该集中到单个 store 对象中。
-
提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
-
异步逻辑都应该封装到 action 里面。
只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。
对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:
注意! Vuex 的状态值在所有组件共享,在路由切换的时候状态值会得到保存,但是!在刷新整个页面之后,状态值会重置,这个是后如果想保留状态值,能且只能与 localStorage 进行配合。
相关博文:https://blog.csdn.net/qq_41772754/article/details/88074103
【重要说明】博文仅作为本人的学习记录,论点和观点仅代表个人而不代表技术的真理,目的是自我学习和有幸成为可以向他人分享的经验,因此有错误会虚心接受改正,但不代表此刻博文无误!
【博客园地址】叫我+V : http://www.cnblogs.com/wjw1014
【CSDN地址】叫我+V : https://wjw1014.blog.csdn.net/
【Gitee地址】叫我+V :https://gitee.com/wjw1014