vuex 状态管理插件
可以理解为,把需要多个组件共享的变量全部存储在一个对象里面。
Vuex 主要解决的问题
- 多个视图依赖同一个状态
- 来自不同视图的行为需要变更同一个状态
使用 Vuex 的好处
- 能够在
vuex中集中管理共享的数据,易于开发和后期维护 - 能够高效地实现组件之间的数据共享,提高开发效率
- 在
vuex中的数据都是响应式的
使用 Vuex 的使用场景
- 比如说用户登录,token令牌。在去服务器发送请求的时候需要携带令牌,不是所有用户都给你请求的,只针对登录后的用户给你请求。
- 比如,用户的头像、地理位置;商品的收藏、购物车中的物品。
安装 Vuex
- npm install vuex --save(不加-dev因为生产环境也需要用到vuex)
- 插件一般在main.js中引用,但vuex的东西比较多,我们一般会像引入router一样,我们在src里建一个文件;
通常在src下建名为仓库:store(仓库)的文件,在store文件的index.js里进行创建对象,导出等工作,然后再在main中引入 store下面的index.js:
import Vue from "vue";
import Vuex from "vuex"; // 引用
Vue.use(Vuex); // 使用
// 导出store独享
export default new Vuex.Store({
// 这边要注意,不是直接new一个Vuex就行了,而是Vuex里面有个属性叫Store,传入一些想要的参数
state: {}, // 保存状态的,把它想象成data{}
mutations: {}, // 想象成methods
actions: {}, // 需要处理异步的方法
getters: {}, // 想象成计算属性computed
modules: {} // 模块
});
main.js:
import Vue from 'vue'
import App from './App'
import store from './store'
new Vue({
el: '#app',
router,
store,
i18n,
render: h => h(App)
})
Vuex核心概念:
vuex提出使用单一状态树,英:Single Source of Truth。vue推荐你只使用一个store,不要去搞一大堆的store,不方便以后维护。
-
State:保存共享状态的地方。姑且可以当作是data中的属性。在组件中使用state:$store.state.属性
-
Getters:类似于组件里面的计算属性,定义在vuex里
计算属性:当我的某一个数据经过一系列变化以后再在我们界面上展示的时候,可以用计算属性。
-
传参:可以接受两个参数例如(state,getters),getters是
getters下的方法。 -
组件中调用:
{{$store.getters.moreAgeStu(8)}}
state:{
students:[{name:'lihua',age:30},{},{}...]
},
getters:{
// 筛选出年龄大于18的学生
more20stu(state){
return state.students.filter(item => item.age > 20)
},
// 筛选出年龄大于18的学生的长度,可以传参,使用more20stu
// 可以接受两个参数,getters可以获取getters下的方法
more20stuLength(state,getters){
return getters.more80stu.length
},
//筛选出年龄大于age的学生,age是可以传参的
moreAgeStu(state){
// return function(age){
// return state.students.filter(s => s.age >age)
// }
return age=>{
return state.students.filter(s => s.age >age)
}
}
}
// 组件中使用:
{{$store.getters.more20stu}}
{{$store.getters.more20stuLength}}
{{$store.getters.moreAgeStu(8)}}
- Mutation:方法可以看作是methods,如果想要改变变量,要通过mutation方法,这样devool里可以跟踪到数据的变化。
在通过mutation更新数据的时候,有可能我们希望携带一些额外的参数, 参数被称之为mutation的载荷payload。
-
传参:
-
普通:可以接受两个参数例如(state,count),count是
传参,可以是很多格式。 -
特殊:
changeCount(state,payload){ state.count = payload.count}payload 是一个对象 -
组件methods里调用(有两种风格):
-
普通:
this.$store.commit('incrementCount',count) -
特殊:
this.$store.commit({ type:'changeCount', count:100 })type事件类型count传参
// 普通的提交方式
mutation:{
incrementCount(state,count){
state.couter += count
},
addStudent(state,stu){
state.students.push(stu)
}
}
// 组件的methods里, @click='addCount(8)' count 加8
// 普通的提交方式 commit(方法名字,传参)
addCount(count){
this.$store.commit('incrementCount',count)
},
// @click='addStudent' 新增一项
addStudent(){
const stu = {id:115, name:'alan',age:35}
this.$store.commit('addStudent',stu)
}
// mutation的另一种提交风格
// 把我们提交的东西全部放到一个对象里面,设置提交类型(上面的incrementCount)的时候,可以在对象里面添加一个属性type
this.$store.commit({
type:'changeCount', // 事件类型
count:100 // 传参
})
// 这种提交风格 需注意组件中methods的写法
changeCount(state,payload){
console.log(payload) // payload是个对象,打印可以发现{type:'changeCount',count:100}
state.count = payload.count
}
mutation 上面通过commit进行提交是一种普通的方式,还提供了另外一种风格,他是一个包含type属性的对象。需要注意payload是一个对象了。
- 思路:
- 在mutation中,我们定义了很多事件类型(也就是方法名称),当我们的项目增大时,Vuex管理的状态越来越多,需要更新状态的情况越来越多,mutation中的方法越来越多
- 由于store里面的index.js中,mutations的方法名,会跟在组件中commint调用的方法名一样,所以官方推荐写成一个常量
- 把mutations抽出来,在store文件里面新建一个mutations-type.js
只有文件export default 才可以import 起个名字 from './compontes/HelloVuex'; 没有export default (export const的形式) :import { } from './compontes/HelloVuex'
两种mutation风格的写法:
项目中,通常把mutations里的方法大写
-
Action:异步操作
通常情况下,Vuex要求我们mutation中的方法必须是同步方法;
主要的原因是当我们使用detools时,可以devtools可以帮助我们捕捉mutation的快照
但是如果是异步操作,那么devtools将不能很好的跟踪这个操作什么时候会被完成
如果你在mutations使用异步方法例如setTimeout,那么就会出现devtools里面跟踪不了数据的问题
Action类似于Mutation,但是是用来代替Mutation进行异步操作的。
-
传参:
-
可以接受两个参数例如
aUpdateInfo(context,payload),context是上下文(跟getters的第二个参数getters不同,注意区分,这里的context是能获取到mutations里的方法类型),payload是传参。 -
组件里调用:
-
this.$store.dispatch('aUpdateInfo','我是传参')mutation 是commit,actions是dispatch
mutations:{
updateInfo(state){
state.info.name = 'coder'
}
},
// Action:异步操作里再通过Mutation修改我们的状态
actions:{
// actions 参数context 上下文
aUpdateInfo(context,payload){
setTimeout(()=>{
context.commit('updateInfo') // 调用上面的mutations里的方法
console.log(payload) // 打印出 我是传参
},1000)
}
}
// 组件中使用
updateInfo(){
this.$store.dispatch('aUpdateInfo','我是传参') // mutation 是commit,actions是dispatch
}
补充一下actions的写法:
actions:{
// context 对象的解构写法 {state,commit,rootState}
// 这里的rootState是指整个 Vuex Store 中所有模块的状态集合,可以用于跨模块访问数据
incrementSum({state,commit,rootState是指整个 Vuex Store 中所有模块的状态集合,可以用于跨模块访问数据}){
if((state.count = rootState.count) % 2 ===1){
commit('increment')
}
}
}
- Module:模块
// 由于vue使用单一状态树,state内容会很多,变得臃肿,推荐使用模块
// 每个模块都可以拥有自己的state,mutaitons,actions,getters
modules:{
a:{
state:{},
mutaitons:{},
actions:{},
getters:{}
},
b:{
....
},
}
// 定义模块使用后,用到state里的name属性,需要$store.a.state.name
// mutations 和 getters 可以不用.a直接使用
vuex文件夹的目录组织