1. vuex基础
1.1 概念和作用解析
- 官方解释: Vuex是一个专为Vue.js 应用程序开发的状态管理模式。
- 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- Vuex也集成到Vue 的官方调试工具
devtools extension
,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能
- 状态管理到底是什么?
- 状态管理模式、集中式存储管理这些名词听起来就非常高大上,让人捉摸不透。
- 其实,你可以简单的将其看成把需要多个组件共享的变量全部存储在一个对象里面。
- 然后,将这个对象放在顶层的Vue实例中,让其他组件可以使用。
- 那么,多个组件是不是就可以共享这个对象中的所有变量属性了呢?
- 如果是这样的话,为什么官方还要专门出一个插件Vuex呢?难道我们不能自己封装一个对象来管理吗?
- 当然可以,只是我们要先想想VueJS带给我们最大的便利是什么呢?没错,就是响应式。
- 如果你自己封装实现一个对象能不能保证它里面所有的属性做到响应式呢?当然也可以,只是自己封装可能稍微麻烦一些。
- 不用怀疑,Vuex就是为了提供这样一个在多个组件间共享状态的插件,用它就可以了。
1.2 管理什么状态呢
- 但是,有什么状态时需要我们在多个组件间共享的呢?
- 如果你做过大型开放,你一定遇到过多个状态,在多个界面间的共享问题。
- 比如用户的登录状态、用户名称、头像、地理位置信息等等。
- 比如商品的收藏、购物车中的物品等等。
- 这些状态信息,我们都可以放在统一的地方,对它进行保存和管理,而且它们还是响应式的(待会儿我们就可以看到代码了,莫着急)
2. vuex的配置
-
在
src
下新建文件夹store
并创建一个store.js
文件 -
store.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ // 常用属性 state:{}, mutations:{}, actions:{} }); // 导出store export default store
-
在
main.js
中引入import store from './store/store' /* eslint-disable no-new */ new Vue({ render: h => h(App), store }).$mount('#app')
3. vuex实现状态管理
3.1 Vuex状态管理图例
3.2 多界面的状态管理
3.2.1 案例
如图所示上下两个部分是不同组件显示的内容,我们要实现点击加减按钮,上下两个数字都会改变,实际上这两个数字是由共享变量counter
决定的。
- 上面这个案例我们可以通过父子组件通信实现
- 但是当两个组件不存在父子关系时,我们需要用
Vuex
来实现
3.2.2 实现步骤
实现思路
- 提取出一个公共的store对象,用于保存在多个组件中共享
的状态 - 将store对象放置在new Vue对象中,这样可以保证在所有
的组件中都可以使用到 - 在其他组件中使用store对象中保存的状态即可
- 通过
this.$store.state.
属性的方式来访问状态 - 通过
this.$store.commit('mutation中方法')
来修改状态
- 通过
- 注意事项:
- 我们通过提交
mutation
的方式,而非直接改变
store.state.count
。 - 这是因为Vuex可以更明确的追踪状态的变化,所以不要直接
改变store.state.count
的值。
- 我们通过提交
代码
store.js
const store = new Vuex.Store({
state:{
counter: 100,
},
mutations:{
increment(state){
state.counter++;
},
decrement(state){
state.counter--;
}
},
});
Home.vue
<template>
<div id="home">
<p>-------------------------</p>
<h2>{{$store.state.counter}}</h2>
</div>
</template>
App.vue
<template>
<div id="app">
<h2>{{$store.state.counter}}</h2>
<button @click="addtion">+</button>
<button @click="subtraction">-</button>
<home></home>
</div>
</template>
methods:{
addtion(){
this.$store.commit('increment');
},
subtraction(){
this.$store.commit('decrement');
}
},
4. vuex - getters的使用
当我们需要从store中获取一些state变异后的状态,比如需要对数组进行筛选。虽然可以通过计算属性computer
在用filter
进行筛选,但是当另一个组件也想这样的话,代码就会显得繁琐。这时我们可以使用getters
前提:
state:{
students:[
{id:1, name:'lili', age: 18},
{id:2, name:'amy', age: 15},
{id:3, name:'daming', age: 28},
{id:4, name:'lisi', age: 21},
]
},
-
对
students
数组进行筛选,选出age
大于20的getters:{ getAge(state){ return state.students.filter(s => s.age > 20); }, },
-
使用
<h2>获取年龄大于20的数组</h2> <p>{{$store.getters.getAge}}</p>
-
-
求
getAge
的数组长度- 这时需要用到
getters
里的getAge
,那么就要把getters
作为参数传进去 getters
里面的方法第一个参数是state
;第二个参数就是getters
,就算第二个参数你起了一个别的名字,他也是表示getters
;没有第三个
getters:{ getLength(state, getters){ return getters.getAge.length }, },
-
使用
<h2>获取年龄大于20的数组长度</h2> <p>{{$store.getters.getLength}}</p>
- 这时需要用到
-
从组建中传一个参数过来,获取年龄大于10的数组
- 获取组件传过来的参数,就要返回一个带参数的函数
getters:{ getAgeStu(state){ // return function(age){ // return state.students.filter(s => s.age > age); // } return age => { return state.students.filter(s => s.age > age); } } },
-
使用
<h2>获取年龄大于10的数组</h2> <p>{{$store.getters.getAgeStu(10)}}</p>
5. vuex - mutation
5.1 vuex - mutation传递参数
- 在通过
mutation
更新数据的时候,有可能我们希望携带一些额外的参数- 参数被称为是
mutation
的载荷(Payload
)
- 参数被称为是
5.1.1 传递单个参数
- 传递一个参数给store,点击+5按钮数字加5,也可以传递10,让他+10
App.vue
<template>
<div id="app">
<h2>{{$store.state.counter}}</h2>
<button @click="addCounter(5)">5+</button>
</div>
</template>
methods:{
addCounter(count){
this.$store.commit('addCounter', count);
}
},
store.js
mutations:{
addCounter(state,count){
state.counter += count;
}
},
5.1.2传递对象
往store
里的students
添加元素
App.vue
<button @click="addNewArg">添加学生</button>
addNewArg(){
const obj = {id:5, name:'张强', age: 68};
this.$store.commit('addNewArg', obj);
}
store.js
mutations:{
addNewArg(state,obj){
state.students.push(obj);
}
},
5.2. vuex - mutation提交方式补充
- 以对象的形式提交
App.vue
addCounter(count){
// this.$store.commit('addCounter', count);
this.$store.commit({
type: 'addCounter',
count
})
},
store.js
addCounter(state,payload){
state.counter += payload.count;
//console.log(payload);
},
-
打印一下传过来的参数
payload
- 并不只是
count
,他包含了count
和type
- 并不只是
5.3 vuex - mutation的类型常量
在组件中使用mutation
中的方法时,需要来回复制,有的人还会手写,这样很容易出错
-
官方推荐我们把函数名定义为一个常量
-
新建一个文件
mutations.types.js
文件export const INCREMENT = 'increment'
-
在组件和
store.js
中进行更改- 组件中
// 引入文件 import {INCREMENT} from './store/mutations-types' methods:{ addtion(){ this.$store.commit(INCREMENT); }, },
store.js
// 引入文件 import {INCREMENT} from './store/mutations-types' mutations:{ [INCREMENT](state){ state.counter++; }, }
6. vuex - actions
6.1 actions的基本定义
-
actions
的功能跟mutation
基本相同,不同的是actions
一般用来代替mutation
实现异步操作 -
mutation
中也可以实现异步操作,但是我们一般不在mutation
中写异步函数 -
actions
里函数参数为context
actions:{ actionInfo(context, payload){ return new Promise((resolve, reject) => { setTimeout(() => { context.commit('updateInfo'); console.log(payload); resolve('111'); }, 1000) }) } }
7. vuex - modules
- 在大型项目中,如果把所有需要共享的数据都存放在
state
中,就会显得非常的臃肿 - vuex为我们提供了
modules
属性,我们可以定义很多不同的模块,每个模块里都有自己的state、actions、mutations
等等
const moduleA = {
state:{
name: '闫刚'
},
mutations:{
changeName(state){
state.name = "李想";
}
},
actions:{},
getters:{}
}
const store = new Vuex.Store({
modules:{
a: modulesA
}
})
7.1 使用详解
-
引用
state
里的属性<p>{{$store.state.a.name}}</p>
- 通过
devtools
我们可以查看到,根store
下的state
里包含了我们在modules
里定义的模块a
- 所有想使用a里的state,直接
$store.state.a.属性名
- 通过
-
mutation
<button @click="changeName">更改name</button> changeName(){ this.$store.commit('changeName'); }
mutations
的使用方法同根store
里的一样- 系统在识别到这个方法时会先查看根
store
里的mutations
是否有同名的,没有的话再去模块中找。所以起函数名不要起一样的
-
getters
getters
的使用方法跟根store
里的一样- 方法参数也一样,不同的是,模块里的可以通过参数
rootState
引用根state
里的属性
<p>{{$store.getters.fullName}}</p> <p>{{$store.getters.fullName2}}</p> <p>{{$store.getters.fullName3}}</p>
getters:{ fullName(state){ return state.name += '1111'; }, fullName2(state, getters){ return getters.fullName + '222'; }, fullName3(state, getters, rootState){ return getters.fullName + rootState.counter; } }
-
通过
devtools
,我们可以发现,模块a里定义的getteras
,被放到了根getters
里
-
actions
- 使用方法跟根
actions
里的一样,不同的是模块里的actions
方法参数context
包含的内容不同
- 当我们需要使用根节点下的属性方法时,可以调用
context.rootGetters
等
actions:{ updateName(context){ //console.log(context); setTimeout(() => { context.commit('changeName', '明明'); },1000); } },
- 使用方法跟根