目录
1.Vuex是用来做什么的?
Vuex是一个专为Vue.js应用程序开发的状态管理模式
什么是状态管理?
把多个组件需要的共享变量全部存储在一个对象里面,然后将这个对象放在顶层的Vue实例中,让其它组件可以使用
管理什么状态?
比如用户的登录状态、用户名称、头像、地理信息位置
比如商品的收藏、购物车中的物品
这些状态信息,我们都可以放在统一的地方,对它进行保存和管理,而且它们还是响应式的
2.单界面的状态管理
State:状态
View:视图层,可以针对State的变化显示不同的信息
Actions:主要是用户的各种操作:点击、输入等,会导致State的变化
<template>
<div id="app">
<h2>{{message}}</h2>
<h2>{{counter}}</h2>
<button @click="counter++">+</button>
<button @click="counter--">-</button>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: '我是App组件',
counter: 0
}
}
}
</script>
<style>
</style>
3.多界面的状态管理
小案例
①提取一个公共的store对象,用于保存在多个组件中共享的状态。
新建store文件夹,创建index.js
index.js
import Vue from 'vue'
import Vuex from 'vuex'
//1.安装插件
Vue.use(Vuex)
//2.创建对象
const store = new Vuex.Store({
state: {
counter: 100
},
mutations: {
increment(state) {
state.counter++;
},
decrement(state) {
state.counter--;
}
}
})
//3.导出store对象
export default store
②将store对象放置在new Vue对象中,这样可以保证在所有组件中都可以使用到
main.js
import Vue from 'vue'
import App from './App'
import store from "./store";
Vue.config.productionTip = false
new Vue({
el: '#app',
store,
render: h => h(App)
})
③在其他组件中使用store对象保存的状态
通过this.$store.state属性的方式来访问状态
通过this.$store.commit('mutation中方法')来修饰状态
HelloVuex.vue
<template>
<div>
<h2>{{$store.state.counter}}</h2>
</div>
</template>
<script>
export default {
name: "HelloVuex"
}
</script>
<style scoped>
</style>
App.vue
<template>
<div id="app">
<h2>{{$store.state.counter}}</h2>
<button @click="addition">+</button>
<button @click="subtraction">-</button>
<hello-vuex/>
</div>
</template>
<script>
import HelloVuex from "./components/HelloVuex";
export default {
name: 'App',
components: {
HelloVuex
},
methods: {
addition() {
this.$store.commit('increment');
},
subtraction() {
this.$store.commit('decrement');
}
}
}
</script>
<style>
</style>
注意:我们通过提交mutation的方式,而非直接改变store.state.count
这是因为Vuex可以更明确地追踪状态的变化,所以不要直接改变store.state.count的值
4.单一状态树
Vuex使用了单一状态树来管理应用层级的全部状态
也就是说所以的共享状态信息都保存在一个store对象中,不保存在多个对象中,这样方便管理和维护
5.Getters的基本使用
有时候,我们需要从store中获取一些state变异后的状态
修改store对象
const store = new Vuex.Store({
state: {
counter: 100,
students: [
{id: 110, name:'fyx', age: 18},
{id: 111, name:'cxl', age: 20},
{id: 112, name:'pjt', age: 22}
]
},
mutations: {
increment(state) {
state.counter++;
},
decrement(state) {
state.counter--;
}
},
getters: {
powerCounter(state) {
return state.counter * state.counter
},
more20stu(state) {
return state.students.filter(s => s.age > 20)
},
//getters可作为参数
more20stuLength(state ,getters) {
return getters.more20stu.length
},
//getters里面的函数如果想传参数
moreAgeStu(state) {
return age => {
return state.students.filter(s => s.age > age)
}
}
}
})
修改App.vue里面的template标签内容
<template>
<div id="app">
<h2>{{$store.state.counter}}</h2>
<button @click="addition">+</button>
<button @click="subtraction">-</button>
<hello-vuex/>
<h2>...Vuex相关内容...</h2>
<h2>{{$store.getters.powerCounter}}</h2>
<h2>年龄大于20的学生信息:{{$store.getters.more20stu}}</h2>
<h2>年龄大于20的学生人数:{{$store.getters.more20stuLength}}</h2>
<h2>年龄大于x的学生人数,x自己传:{{$store.getters.moreAgeStu(18)}}</h2>
</div>
</template>
6.Mutation传递参数
在通过mutation更新数据的时候,有可能我们希望携带一些额外的参数
这个参数被认为是mutation的载荷(Payload)
如果你想传的参数不止一个,我们通常会传一个对象
修改App.vue
<button @click="addCount(5)">+5</button>
<button @click="addCount(10)">+10</button>
<button @click="addStudent">添加学生</button>
methods: {
addition() {
this.$store.commit('increment');
},
subtraction() {
this.$store.commit('decrement');
},
addCount(count) {
this.$store.commit('incrementCount', count)
},
addStudent() {
const stu = {id: 113, name: 'gy', age: 25}
this.$store.commit('addStudent', stu)
}
}
修改store对象的mutations
mutations: {
increment(state) {
state.counter++;
},
decrement(state) {
state.counter--;
},
incrementCount(state, count) {
state.counter += count
},
addStudent(state, stu) {
state.students.push(stu)
}
},
7.Mutation的另一种提交风格
//1.普通的提交封装
this.$store.commit('incrementCount', count)
//2.特殊的提交封装
this.$store.commit({
type: 'incrementCount',
count
})
对应于mutations中的写法
incrementCount(state, payload) {
// state.counter += count;
state.counter += payload.count;
}
这里传过来的payload其实就是前面commit里面的对象
8.mutation的响应规则
Vuex的store中的state是响应式的,当state中的数据发生改变时,Vue组件会自动更新,页面会发生变化
修改App.vue
<h2>....info对象内容...</h2>
<h2>{{$store.state.info}}</h2>
<button @click="updateInfo">修改信息</button>
修改store对象
在mutations中添加方法
updateInfo(state) {
state.info.name='hzr'
// state.info['address'] = 'Los Angeles'
Vue.set(state.info, 'address', 'Los Angeles')
// delete state.info.age
//该方法做不到响应式
Vue.delete(state.info, 'age')
}
点击按钮之后
9.vuex-mutations的类型常量
当项目增大时,mutations里面的方法会很多,官方建议将方法名抽成常量,commit提交的时候也用常量
10.Mutation同步函数
Vuex要求我们Mutations中的方法必须是同步方法
因为我们在使用devtools时,devtools可以帮助我们捕捉mutation的快照
但如果是异步操作,那么devtools将不能很好地追踪这个操作什么时候会被完成
Action类似于Mutation,是用来代替Mutation进行异步操作的
<h2>....info对象内容...</h2>
<h2>{{$store.state.info}}</h2>
<button @click="updateInfo">修改信息</button>
App.vue里面的methods中的方法
updateInfo() {
// this.$store.commit('updateInfo')
this.$store
.dispatch('aUpdateInfo', '我是携带的信息')
.then(res => {
console.log('里面完成了提交')
console.log(res)
})
}
store对象里mutations的updateInfo方法同上
actions: {
//context: 上下文
aUpdateInfo(context, payload) {
return new Promise((resolve, reject) => {
setTimeout(() => {
context.commit('updateInfo')
console.log(payload)
resolve('2222') //一旦执行了resolve(),就去执行then()
}, 1000)
})
}
},
修改信息并打印携带的信息之后,在App.vue里面提示"里面已完成提交",并且打印从aUpdateInfo函数传来的信息
11.modules的使用
Modules是模块的意思
Vue使用单一状态树,这意味着很多状态都会交给Vuex来管理
为了解决这个问题,Vuex允许我们将store分割成模块(Module),而每个模块拥有自己的state,mutations,actions,getters等
<h2>...modules中的内容...</h2>
<h2>{{$store.state.a.name}}</h2>
<button @click="updateName">修改名字</button>
<h2>{{$store.getters.fullname}}</h2>
<h2>{{$store.getters.fullname2}}</h2>
<h2>{{$store.getters.fullname3}}</h2>
<button @click="asyncUpdateName">异步修改名字</button>
methods中的方法
updateName() {
this.$store.commit('updateName', 'LiSi')
},
asyncUpdateName() {
this.$store.dispatch('aUpdateName')
}
store对象中的modules
modules: {
a: moduleA
}
const moduleA = {
state: {
name: 'ZhangSan'
},
mutations: {
updateName(state, payload) {
state.name = payload;
}
},
getters: {
fullname(state) {
return state.name + '1111'
},
fullname2(state, getters) {
return getters.fullname + '222'
},
//调用根state中的变量
fullname3(state, getters, rootState) {
return getters.fullname2 + rootState.counter
}
},
actions: {
aUpdateName(context) {
setTimeout(() => {
context.commit('updateName', 'WangWu')
}, 1000)
}
},
}
点击第一个按钮
点击第二个按钮