【前端Vue】Vuex
2021-01-27 本文已影响0人
itlu
1. Vuex介绍和作用
1.1 Vuex 能做什么?
- 官方解释:
Vuex
是一个专为Vue.js
应用程序开发的状态管理模式
。它采用集中式存储管理
应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex
也集成到Vue
的官方调试工具devtools extension
,提供了诸如零配置的time-travel
调试、状态快照导入导出等高级调试功能。
1.2 状态管理又是什么?
-
其实,可以简单的将其看成把需要多个组件共享的变量全部存储在一个对象里面。
-
然后,将这个对象放在顶层的
Vue
实例中,让其他组件可以使用。 -
那么,多个组件就可以共享这个对象中的所有变量属性。
1.3 难道我们不能自己封装一个对象来管理吗?官方还需要专门出一个插件 Vuex?
看看自己写的
const Store = {
state: {},
mutations: function () {
}
// ....
};
// 将 Store对象挂载到 Vue 实例
Vue.prototype.Store = Store; // 但是这样挂载的对象不具备响应式
自己定义一个全局状态管理
-
当然可以,只是我们要先想想
VueJS
带给我们最大的便利是什么呢?没错,就是响应式。 -
如果你自己封装实现一个对象能不能保证它里面所有的属性做到响应式呢?当然也可以,只是自己封装可能稍微麻烦一些。
-
不用怀疑,
Vuex
就是为了提供这样一个在多个组件间共享状态的插件,用它就可以了。
1.4 管理些什么状态?
-
用户的登录状态、用户名称、头像、地理位置信息等等。
-
还有比如商品收藏、购物车物品。
2. Vuex 的安装
- 使用
npm install vuex --save
命令安装Vuex
为运行时依赖。
3. Vuex 的使用
- 在
src/
下创建一个index.js
文件,安装Vuex
和创建Vuex.Store
对象并导出。
import Vue from 'vue';
import Vuex from 'vuex';
// 安装 Vuex
Vue.use(Vuex);
const store = new Vuex.Store({
/**
*
*/
state: {
counter: 1000
},
/**
*
*/
mutations: {},
/**
* 有异步操作的时候再actions中进行
*/
actions: {},
getters: {}
});
// 导出是方便 在 main.js 中挂载
export default store;
创建Vuex.Store对象并导出
- 在
main.js
中导入store
对象,并挂载到Vue
实例上:
- 此时在全局就可以使用
store
中的内容了,但是不建议直接操作state
中的数据。
<div>
<h2>{{$store.state.counter}}</h2>
</div>
3.1 Vuex小案例 - vuex的Mutations
Vuex小案例- 安装
vuex
为运行时依赖npm install vuex --save
;
- 创建一个
store/inidex.js
文件,创建Vue.Store
实例。
import Vue from 'vue';
import Vuex from 'vuex';
// 安装 Vuex
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
counter: 666
},
mutations: {
increment(state) {
state.counter++;
},
decrement(state) {
state.counter--;
}
}
});
// 导出store
export default store;
- 在
main.js
入口文件中引入store
并挂载到Vue
实例上。
- 创建一个
HelloVuex
组件,获取$store.state.counter
数据展示。
<template>
<h2>
{{$store.state.counter}}
</h2>
</template>
<script>
export default {
name: "hello-vuex"
}
</script>
<style scoped>
</style>
- 在
App.vue
中使用HelloVuex
并使用Store
中的mutations
改变counter
。
<template>
<div id="app">
<h2>我是App组件</h2>
<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>
操作流程
4. Vuex的几个核心概念
-
State
; -
Getters
; -
Mutations
; -
Action
; -
Module
;
4.1 State 单一状态树
- 将所有的状态信息,保存到一个
Store
对象中保存起来,而不是多个。
4.2 Getters
-
getters
有点类似computed
计算属性。
Getters 进行基本的操作
import Vue from 'vue';
import Vuex from 'vuex';
// 安装Vuex
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
counter: 100,
students: [
{name: '张三', age: 23},
{name: '陆小凤', age: 16},
{name: '花满楼', age: 15},
{name: '西门吹雪', age: 30},
]
},
/**
* 类似计算属性
*/
getters: {
/**
* 计算 state.counter的平方
* @param state
*/
powCounter(state) {
return state.counter * state.counter
},
/**
* 想筛选年龄大于 20岁的学生的信息
*/
more20Stu(state) {
return state.students.filter(stu => stu.age >= 20);
}
}
});
export default store;
<h2> A powCounter : {{$store.getters.powCounter}}</h2>
<h2> A more20Stu : {{$store.getters.more20Stu}}</h2>
getters作为参数 -> 计算满足条件的学生个数
/**
* 想筛选年龄大于 20岁的学生的信息
*/
more20Stu(state) {
return state.students.filter(stu => stu.age >= 20);
},
/**
* 获取年龄大于 20 岁学生的个数
* @param state
* @param getters
* @returns {number}
*/
more20StuLength(state, getters) {
return getters.more20Stu.length
<h2> HelloVuex more20StuLength : {{$store.getters.more20StuLength}}</h2>
Getters 中如果接受外界传递的参数
-
Getters
中接收外界传递的参数可以以返回一个函数的方式进行,在返回的函数中传递参数。
moreAgeStu(state) {
// 这里返回的是一个函数 在返回的函数中传递参数
return (age) => state.students.filter(stu => stu.age >= age)
}
<h2> HelloVuex moreAgeStu : {{$store.getters.moreAgeStu(20)}}</h2>
4.3 Mutations
-
Mutations
:Vuex
的Store
状态的更新唯一的方式。
mutations 中传递参数
mutations 中传递参数mutations的提交风格
mutation的提交风格值得注意的是此时传递过去的参数是一个对象。
mutations响应规则及原理
-
Vuex
的store
中的state
是响应式的, 当state
中的数据发生改变时,Vue
组件会自动更新。
mutation 响应式的要求
-
提前在store中初始化好所需的属性。
-
当给
state
中的对象添加或删除属性时, 使用下面的方式:
Vue.set(state.info , 'address','大雷音寺') // 这样修改是响应式的
Vue.delete(state.info, 'age') // 这也是响应式的
// 或者使用新对象给旧对象赋值
state.info = {name: '王五', age: 25, height: 1.5555, address: '西山区'}
mutations类型常量
mutation类型常量mutation 同步函数
- 通常情况下,
Vuex
要求我们Mutation
中的方法必须是同步方法。主要的原因是当我们使用devtools
时, 可以devtools
可以帮助我们捕捉mutation
的快照。
- 比如之前执行更新的代码中,如果使用异步的方式进行对象属性数据的更新,会发现在
devtools
中的state
无法追踪到数据的变化。所以,通常情况下,不要再Mutations
中进行异步操作。
// store/index.js
updateInfo(state) {
// 在 mutations 中进行异步操作
setTimeout(() => {
state.info.name = "孙悟空"
},1000)
}
// App.vue
updateStoreInfo() {
this.$store.commit('updateInfo');
}
在mutations中使用异步方法出现数据变化和devtools不一致
4.4 actions
-
不要再
Mutation
中进行异步操作,但是某些情况, 我们确实希望在Vuex
中进行一些异步操作, 比如网络请求, 必然是异步的. 这个时候怎么处理呢? -
在
Action
中进行操作,Action
类似于Mutation
, 但是是用来代替Mutation
进行异步操作的。
actions的基本使用
-
context
是什么?context
是和store
对象具有相同方法和属性的对象,也就是说, 我们可以通过context
去进行commit
相关的操作, 也可以获取context.state
等,但是注意, 这里它们并不是同一个对象。
// store/index.js
actions: {
aUpdateInfo(context) {
setTimeout(() => {
context.commit('updateInfo')
}, 1000)
}
}
// App.vue
updateStoreInfoForActions() {
this.$store.dispatch('aUpdateInfo');
}
actions也支持 payload
- 在函数中传递
payload
:
/**
* 传递 payload
*/
updateStoreInfoForActions() {
this.$store.dispatch('aUpdateInfo', {
message: '我是payload',
success: function () {
console.log('操作成功')
}
});
}
- 在
actions
中接收参数:
actions: {
aUpdateInfo(context, payload) {
setTimeout(() => {
context.commit('updateInfo')
console.log(payload.message);
payload.success()
}, 1000)
}
}
actions 中使用 Promise 处理异步操作
- 使用
Promise
处理异步请求,将Promise
对象返回:
/**
* 传递payload参数,使用Promise的方式处理异步请求
* @param context
* @param payload
*/
aUpdateInfo(context, payload) {
return new Promise((resolve, reject) => {
setTimeout(() => {
context.commit('updateInfo')
resolve(payload.message + payload.success())
}, 1000)
})
}
- 处理
Promise
对象的then
:
/**
* 传递 payload
*/
updateStoreInfoForActions() {
this.$store.dispatch('aUpdateInfo', {
message: '我是payload',
success: function () {
console.log('操作成功')
}
}).then(value => {
console.log(value);
})
}
4.5 modules
-
Vue
使用单一状态树,那么也意味着很多状态都会交给Vuex
来管理。当应用变得非常复杂时,store
对象就有可能变得相当臃肿,为了解决这个问题,Vuex
允许我们将store
分割成模块(Module
), 而每个模块拥有自己的state、mutations、actions、getters
等。
Module局部状态
-
我们在
moduleA
中添加state、mutations、getters
。 -
mutations
和getters
接收的第一个参数是局部状态对象。 -
虽然, 我们的
doubleCount
和increment
都是定义在对象内部的,但是在调用的时候, 依然是通过this.$store
来直接调用的。
Actions的写法
- 局部状态通过
context.state
暴露出来,根节点状态则为context.rootState
:
- 如果
getters
中也需要使用全局的状态, 可以接受更多的参数:
5. 项目结构
- 重点是 :
export
import
导入导出。