一、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. 正常访问, 与重构前一样