当前位置: 代码迷 >> 综合 >> 十二、 Vuex 状态管理
  详细解决方案

十二、 Vuex 状态管理

热度:28   发布时间:2023-11-23 10:05:01.0

一、Vuex 概述

1. 官方文档:https://vuex.vuejs.org/zh/Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

2. Vuex简单理解: Vue 应用中的每个组件在 data() 中封装着自己数据属性,而这些 data 属性都是私有的,完全隔离的。 如果我们希望多个组件都能读取到同一状态数据属性,或者不同组件的行为需要更新同一状态数据属 性, 这就需要一个将共享的状态数据属性进行集中式的管理。 这就是 Vuex 状态管理所要解决的问题。

3.上面复制的,我写不出这么深刻的理解。

二、整整试试

1.先创建一个Vue项目,手动安装,vuex Router ,2.x版本然后一顿回车,哈哈哈

2.然后运行一下服务

3.面试爱问:每一个 Vuex 应用的核心就是 store(仓库)

4.在store文件下的index.js中添加 count: 0:

export default new Vuex.Store({state: {count: 0},mutations: {},actions: {},modules: {}
})

5.然后让他在页面中显示,找到views的home.vue:

<template><div class="home"><h1>1111</h1><HelloWorld msg="Welcome to Your Vue.js App"/></div>
</template>

6.效果:

7.用{ {$store.state}}来获取状态对象,

<template><div class="home"><h1>{
   {$store.state.count}}</h1><HelloWorld msg="Welcome to Your Vue.js App"/></div>
</template>

8.效果:

 9.我们可以改变一下这个值count,通过mutations,回到store文件下的index.js中:

 mutations: {increment(state) {state.count++},decrement(state) {state.count--}},

10.再回到views的home.vue:

<template><div class="home"><h1>{
   {$store.state.count}}</h1><button @click="add">++</button><button @click="decrement">--</button><HelloWorld msg="Welcome to Your Vue.js App"/></div>
</template>

11.在export default里添加方法:

export default {name: "Home",components: {HelloWorld,},methods: {add() {},decrement() {},},
};

12.官网--可以从组件的方法提交一个变更-----this.$store.commit:

methods: {add() {this.$store.commit("increment");},decrement() {this.$store.commit("decrement");},},

13.现在可以实现点击++时,0++,点击--时,0--

14.就像官网所说,store当成一个仓库,然后通过在组件中去调用它的内部的方法,来实现对它的改动。

三、试试奥----mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,不能直接调用一个 mutation,需要以相应的 type 调用 store.commit 方法

1.那么,我们可不可以在其他组件中使用它呢,在views的about.vue中,

<template><div class="about"><h1>{
   { $store.state.count }}</h1></div>
</template>

2.结果发现也能拿到。

3.那么,我们可不可以在添加一个新值呢,加一个n,回到store文件下的index.js中:

 mutations: {increment(state, n) {state.count += n},decrement(state) {state.count--}},

在回到views的home.vue:

 methods: {add() {this.$store.commit("increment",10);},decrement() {this.$store.commit("decrement");},},

4.结果发现也能拿到。这叫载荷,可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload)

四、Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

1.在store文件下的index.js中:

    actions: {dec({ commit }) {commit("decrement")},},

2.在组件中使用 this.$store.dispatch('xxx') 分发 action,在回到views的home.vue:

decrement() {// this.$store.commit("decrement");this.$store.dispatch('dec')},

3.测试可以实现减操作。

4.在Action中,结构赋值形式添加一个新值,在store文件下的index.js中:

add({ commit }) {commit("increment", 10)}

在回到views的home.vue:

 add() {// this.$store.commit("increment",10);this.$store.dispatch('add')},

5.测试可以实现加10操作。

6.默认形式添加一个新值,在store文件下的index.js中,把原来的add()注释上,添加:

 add(contxt) {contxt.commit("increment", 10)}

7.测试发现也可以实现加10操作。

五、 派生属性 getter

1. 理解 :

有时候我们需要从 store 中的 state 中派生出一些状态。例如:基于上面代码,增加一个 desc 属性,当 count 值小于 50,则 desc 值为 吃饭 ; 大于等于 50 小于100,则desc 值为 睡觉 ; 大于100 , 则 desc 值为 打豆豆 。这时我们就需要用到 getter 为我们解决。getter 其实就类似于计算属性(get)的对象.组件中读取 $store.getters.xxx 

2.实操

修改 store\index.js ,增加 getters 选项注意:getters 中接受 state 作为其第一个参数,也可以接受其他 getter 作为第二个参数

getters: {desc(state) {if (state.count < 50) {return "吃饭"} else if (state.count < 100) {return "睡觉"} else {return "打豆豆"}}}

修改 views\Home.vue, 显示派生属性的值:

<template><div class="home"><h1>{
   { $store.state.count }}</h1><h2>{
   {$store.getters.desc}}</h2><button @click="add">++</button><button @click="decrement">--</button><HelloWorld msg="Welcome to Your Vue.js App" /></div>
</template>

3.效果:

 

六、Module模块化项目结构

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,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: moduleA,   b: moduleB  }  })

store.state.a // -> moduleA 的状态

store.state.b // -> moduleB 的状态

1.举个例子,修改 store\index.js:

import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)let A = {state: {count: 0}, //存值// 下面都是方法mutations: {increment(state, n) {state.count += n},decrement(state, n) {state.count -= n}},actions: {dec({ commit }) {commit("decrement", 10)},// add({ commit }) {//     commit("increment", 10)// },add(contxt) {contxt.commit("increment", 10)}},getters: {desc(state) {if (state.count < 50) {return "吃饭"} else if (state.count < 100) {return "睡觉"} else {return "打豆豆"}}}
}export default new Vuex.Store({modules: {a: A},})

2.修改views\Home.vue:

<template><div class="home"><h1>{
   { $store.state.count }}</h1><h2>{
   {$store.getters.desc}}</h2><h3>{
   {$store.state.a.count}}</h3><button @click="add">++</button><button @click="decrement">--</button><HelloWorld msg="Welcome to Your Vue.js App" /></div>
</template>

3.效果:

 4.为了保证变量重复的情况下也能使用,我们在index.js中引入,使它变成局部作用:

namespaced: true,

5.在home.vue中:

methods: {add() {// this.$store.commit("increment",10);this.$store.dispatch('a/add')},decrement() {// this.$store.commit("decrement");this.$store.dispatch('a/dec')},},

6.效果:

7.在创建一个变量B:

import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)let A = {namespaced: true,state: {count: 0}, //存值// 下面都是方法mutations: {increment(state, n) {state.count += n},decrement(state, n) {state.count -= n}},actions: {dec({ commit }) {commit("decrement", 10)},// add({ commit }) {//     commit("increment", 10)// },add(contxt) {contxt.commit("increment", 10)}},getters: {desc(state) {if (state.count < 50) {return "吃饭"} else if (state.count < 100) {return "睡觉"} else {return "打豆豆"}}}
}let B = {namespaced: true,state: {count: 0}, //存值// 下面都是方法mutations: {increment(state, n) {state.count += n},decrement(state, n) {state.count -= n}},actions: {dec({ commit }) {commit("decrement", 10)},// add({ commit }) {//     commit("increment", 10)// },add(contxt) {contxt.commit("increment", 10)}},getters: {desc(state) {if (state.count < 50) {return "吃饭"} else if (state.count < 100) {return "睡觉"} else {return "打豆豆"}}}
}export default new Vuex.Store({modules: {a: A,b: B},})

 在home.vue:

<template><div class="home"><h1>{
   { $store.state.count }}</h1><h2>{
   {$store.getters.desc}}</h2><h3>{
   {$store.state.a.count}}</h3><h3>{
   {$store.state.b.count}}</h3><button @click="add">++</button><button @click="decrement">--</button><HelloWorld msg="Welcome to Your Vue.js App" /></div>
</template>

修改方法:

 methods: {add() {// this.$store.commit("increment",10);this.$store.dispatch("a/add");this.$store.dispatch("b/add");},decrement() {// this.$store.commit("decrement");this.$store.dispatch("a/dec");this.$store.dispatch("b/dec");},},

8.效果:

 七、标准项目结构

如果所有的状态都写在一个 js 中,这个 js 必定会很臃肿,Vuex 并不限制你的代码结构。但是它建议你按以下代码结构来构建项目结构:

1. 重构项目结构

1. 1在src下新建一个newStore文件夹, 在此文件夹下创建 index.js,actions.js,mutations.js和modules 目录,在该目录下创建 demo1.js 和demo2.js 

demo1.js:

let A = {namespaced: true,state: {count: 0}, //存值// 下面都是方法mutations: {increment(state, n) {state.count += n},decrement(state, n) {state.count -= n}},actions: AA,getters: {desc(state) {if (state.count < 50) {return "吃饭"} else if (state.count < 100) {return "睡觉"} else {return "打豆豆"}}}
}
export default A

demo2.js :

let B = {namespaced: true,state: {count: 0}, //存值// 下面都是方法mutations: {increment(state, n) {state.count += n},decrement(state, n) {state.count -= n}},actions: {dec({ commit }) {commit("decrement", 10)},// add({ commit }) {//     commit("increment", 10)// },add(contxt) {contxt.commit("increment", 10)}},getters: {desc(state) {if (state.count < 50) {return "吃饭"} else if (state.count < 100) {return "睡觉"} else {return "打豆豆"}}}
}
export default B

 newStore\index.js:

import Vue from 'vue'
import Vuex from 'vuex'import A from './modules/demo1.js'
import B from './modules/demo2.js'Vue.use(Vuex)export default new Vuex.Store({modules: {a: A,b: B},})

在main.js中把原来的注释上,导入新的store,也就是newStore:

import store from './newStore'

在actions.js中:

let AA = {dec({ commit }) {commit("decrement", 10)},add(contxt) {contxt.commit("increment", 10)}
}
export { AA }

2. 正常访问, 与重构前一样