1. 概念和作用解析
- vuex是专为vue.js应用程序开发的状态管理模式
- 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
- 状态管理是什么:
可以简单地将其看成把需要多个组件共享的变量全部存储在一个对象里面,然后将这个对象放在顶层的Vue实例中,让其他组件可以使用 - 自己封装实现一个对象也能保证它里面所有的属性都能做到响应式,不过很麻烦
- 管理什么状态:需要在多个界面共享的状态才放入vuex
2.单界面到多界面状态管理切换
- 在src文件夹里添加一个名为store(仓库)的文件夹,里面放关于vuex的,在store下创建index.js文件
之后在main.js挂载,之后所有vue组件都有$store对象
在app.vue里应用$store.state.counter
3.vuex-devtools和mutations
1.mutations的状态更新
-
vuex状态管理图例
devtools是vue开发的一个浏览器插件,可以记录每一次state改变的状态
我们通过提交mutation的方式修改state,而非直接改变store.state.count,因为vuex可以更明确的追踪状态的变化
mutations的改变是响应式的2. 代码示例,实现点击+counter++,点击-counter–
index.js里,默认参数是state
app.vue里 -
即用
this.$store.state
属性的方法来访问状态,this.$store.commit('mutation中方法')
来修改状态
2.mutations携带参数
- mutation主要包括两部分:
字符串的事件类型
一个回调函数,该回调函数的第一个参数是state - 代码:
//index.js里:
<script>
mutations: {
incrementCount(state,count) {
state.counter += count
}
}
</script>
//app.vue里:
<script>
methods: {
addCount(count) {
this.$store.commit('incrementCount',count)
}
}
</script>
- 如果参数不是一个:
3.mutations的提交风格
- commit进行提交
- 特殊的提交风格:这里的count是一个对象
4.响应规则
- vuex中的store中的state是响应式的,当state中的数据发生改变时,vue组件会自动更新
- 这就要求我们必须遵守一些规则:
提前在store中初始化好所需的属性
当给state中的对象添加新属性时,使用下列方法:
①使用Vue.set(obj,‘属性’,值),属性要加引号
②用新对象给旧对象重新赋值 - 示例
Vue.set(state.info,'address','洛杉矶')
- 删除属性,
delect state.info.age
做不到响应式
响应式的方法:Vue.delect(state.info,'age')
5.类型常量
- 在mutation中,我们定义了很多事件类型(即其中的方法名称),当方法越来越多时,如果不用复制,可能会写错,故我们最好将方法抽成常量
- 代码示例:在store文件夹里添加mutations-type.js的文件
6.同步函数
mutation中的方法必须是同步方法
4.vuex-state单一状态树
- vuex中几个比较核心的概念
state:保存共享状态的地方
getters:类似组件中的计算属性
mutation
action:主要用于异步操作
module:用于划分模块 - vuex提出使用单一状态树来管理应用层级的全部状态
5.vuex-getters
1.getters用法
- 类似于计算属性,什么时候需要用到计算属性:当数据要经历一系列变化再到界面中使用的时候
- 代码示例:getters里面默认参数是state
2.参数传递
- 如果我们希望获取大于20岁学生的数量,而已经有了这个的getters,则可以这样写:
return getters.more20stu.length
2. getters默认是不能传递参数的,若想传入参数,只能让getters本身返回一个函数
6.vuex-actions
- 如果在mutations中进行异步操作,看似改变了,其实state里面并没有修改,无法很好地追踪这次操作的变化
- 用action进行异步操作
- 在action定义的方法有个默认属性为context,可以理解为store对象
- 代码示例
<script>
const store = new Vuex.Store({
state: {
……
},
mutations: {
updateInfo(state) {
state.info.name = 'slineee'
}
}
actions: {
//payload相当于参数
aUpdateInfo(context,payload) {
setTimeout(() => {
//不能用context.state.info.name ='slineee'来修改
//因为修改一定要通过mutation
//异步操作是要在这里增加一个环节,而不是替代这个环节
context.commit('updateInfo')
//1.当一秒后先提交,再回调
payload()
//2.如果里面还需要传递参数
console.log(payload.message);
payload.success()
},1000)
}
},
})
</script>
//App.vue中
<script>
//1.如何回调
methods: {
updateInfo() {
//传一个函数
this.$store.dispatch('aUpdateInfo',() => {
console.log(‘里面已经完成了')
})
}
}
//2.如果里面还需要传递参数:
methods: {
updateInfo() {
this.$store.dispatch('aUpdateInfo',{
message: '我是携带的信息’,
success: () => {
console.log(‘里面已经完成了');
}
}
}
}
</script>
<script>
//3.优雅的写法
aUpdateInfo(context,payload) {
return new Promise(resolve,reject) => {
setTimeout(() => {
context.commit('updateInfo');
console.log(payload);
resolve('11111')
},1000)
}
}
App.vue里
updateInfo() {
this.$store
.dispatch('aUpdateInfo','我是携带的信息')
//then写在这里
.then(res => {
console.log('里面完成了提交');
console.log(res);
})
}
</script>
7.vue-modules
- module是模块的意思,因为vue使用单一状态树,store对象可能变得相当臃肿,为解决这个问题,vuex允许我们将store分割成模块,而每个模块拥有自己的state、mutations、action……
- 示例
- 如果moduleA里的state定义了name,怎么拿到这个name:
$store.state.a.name
,(a会放到state里面) - 如果模块里也有mutations和getters,也是像之前一样去使用,不关心是定义在模块里还是state里
- 示例,若想在一个模块里引用state里的某个属性,在模块里可以有第三个参数rootState,(根节点状态则为context.rootState)
- 补充知识点:对象的解构(解释上面代码为什么没有context)
const person={
name:"slineee",
age:3,
height:178
}
var {name,height,age}=person;
console.log(name) //slineee
console.log(age) //3
console.log(height) //178
- 模板里的actions:使用commit的时候只会用模块里的东西
<script>
const moduleA = {
state:{
name: 'zhangsan'
},
mutations: {
updateName(state,payload) {
state.name = payload
}
}
actions: {
aUpdateName(context) {
setTimeout(() => {
context.commit('updateName','slineee')
},1000)
}
}
}
//App.vue里
methods: {
asyncUpdateName() {
this.$store.dispatch('aUpdateName')
}
}
</script>
8.vuex-store文件夹的目录结构
- 项目结构
- state则是在index.js里定义
import mutations from ''
const state ={}
const store = new Vuex.Store({
state,
mutations
……
})