Vuex的学习
终于又开始学习了!
最近有点瞎忙,哎!
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
状态管理,就是管理的全局变量。
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
1. vuex的使用场景是什么呢?
- 一般来讲,小的单页面应用开发程序不适合使用Vuex,因为还是有点繁琐的。所以,vuex还是比较适合比较大型的单页面应用程序的开发。
- 使用场景,就是全局的变量管理,比如登录的token,以及一些用户信息什么的,很多地方都会使用到,就比较适合全局管理。
- 官方解释:
- 多个视图依赖于同一状态(例如兄弟组件传值)。
- 来自不同视图的行为需要变更同一状态(例如父子组件传值)。
- 还有其他的使用的时候有体会再总结吧!
下面开始介绍怎么使用吧
(就不从基础的开始介绍了吧,直接将store单独抽离出来一个文件开始吧)
使用vue-cli搭建的项目目录结构
可以看出store文件下面有新建了几个js文件,是什么意思呢?
- index.js 是总的状态管理文件
- app.js/ user.js 是分模块的状态管理
- mutation-types.js 是常量集合文件
相当于流程:
在index.js
文件里导入 app.js/user.js
等不同模块,再将这一系列的模块挂载到store对象中。再在 main.js
文件里导入 store
文件,就可以全局管理了,这样也使状态管理更加清晰。
2. vuex的开始与核心概念:
- 首先创建一个store对象
const store = new Vuex.Store({
state: {
count:0
},
getters:{
myCount(state){
return `当前数字是:${state.count}`
}
},
mutations: {
increment(state){
state.count += 1;
}
},
actions:{
myIncrease(context){
context.commit(increment)
}
}
})
可以看出去这个对象包含了四个属性,分别是干什么的呢?
-
state:就是需要全局管理的状态,一般通过
this.$store.state.变量名
来获取其值,一般写在computed
计算属性中。
即在根实例中注册 store 选项,该store 实例会注入到根组件下的所有子组件中
,且子组件能通过 this.$store 访问到。
-
getters: 就是对全局的状态做个处理,比如过滤等操作,可认为是state的计算属性,一般写在
computed
计算属性中。
getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算
。
一般通过this.$store.getters.方法名
来调用其中的方法,getters 接受 state 作为其第一个参数
-
mutations: 改变全局状态的操作(唯一方法),一般写在
methods
中。
记住:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
,它会接受 state 作为第一个参数。
一般通过this.commit('increment')
来调用mutations中的方法
-
actions: 改变状态的复杂业务逻辑,一般写在
methods
中。
action提交的是 mutation,而不是直接变更状态。
action可以包含任意异步操作
。
action 函数接受一个与 store 实例具有相同方法和属性的context
对象,可以调用context.commit
提交一个 mutation,也可通过context.state
和context.getters
来获取 state 和 getters。
其实取值可以使用官方文档的辅助函数:mapState
,mapGetters
,mapMutations
,mapActions
,操作更加简单。
前面的这些 自己总结加上官方的说法,理解之后再看下面的操作,建议去看官方文档
3. store文件分模块抽离
直接上文件内容分析(计算器为例):
index.js :总的模块整合,导入到store对象上
- 记住要先引入vue和vuex
- 再引入分离的模块
- 最后将分离的模块统一引入sotre对象中,通过
modules
属性
import Vuex from "vuex";
import Vue from "vue";
//引入 分离的模块
import app from './app';
import user from './user';
Vue.use(Vuex);
// 分模块管理
const store = new Vuex.Store({
modules:{
app,
user
}
});
export default store
下面看看分离的app.js文件,单独写某个模块的全局状态管理(user.js同)
- 可看出创建了一个app对象,里面包含了store的四个属性,为了可以直接引入到store对象中。
- 里面还引入了
mutation-types
文件,也就是将变量名替换成常量名。因为方法名在组件中使用时,要写成字符串格式,不太方便。- mutations和actions属性包含的方法,除了接收的固定参数,也可接收传参
常量集合里面获取的名字 进行 替换调用字符串的名字
import {Increment,Decrement} from './mutation-types';
const app = {
state:{
count:0
},
getters:{
myCount(state){
return `当前数字是:${state.count}`
}
},
mutations:{
方括号 引入常量代表的变量方法名
[Increment](state,n){ 方法都可传参
state.count += n;
},
[Decrement](state,n){
state.count -= n;
}
},
actions:{
myIncrease(context,obj){
context.commit(Increment,2);方法可传参
},
myDecrease(context){
context.commit(Decrement,2);
}
}
};
export default app
在index.js文件中导入了app.js,再在store对象中引入app模块,相当于整个状态管理全部集中在index.js文件,所以要全局使用的话,还需要将store对象引入到 main.js文件中,并挂载到Vue实例上。
main.js文件
import Vue from 'vue'
import Vuex from 'vuex'
import App from './App'
import router from './router'
import store from './store'
Vue.config.productionTip = false;
Vue.use(Vuex);
new Vue({
el: '#app',
components: { App },
template: '<App/>',
router,
store,
});
最后看下,常量集合文件mutation-types.js,就是将全局的变量名,可以统一命名成常量名。导入这个文件,则名字就可以全局规范,提高代码的可读性
例如规范了 两个函数的名字
export const Increment= "increment";
export const Decrement= "decrement";
4.组件中具体使用 (计数器)
- 可看出使用了辅助函数,
mapState
,mapGetters
,mapMutations
,mapActions
,使用es6的扩展运算符,直接展开数组,每个属性都有一个辅助函数。
- 导入了 mutation-types,常量集合文件,引用时可以不用字符串
...mapMutations([Increment,Decrement])
使用写法
...mapActions(['myIncrease','myDecrease'])
未使用写法
- 注释部分,调用store中mutation中的方法,改变全局状态,其实实现的功能是一样的:
- 方法(1):
this.$store.commit('increment');
- 方法(2):映射store中的方法,并直接调用(推荐)
import {mapMutations} from 'vuex';
this.increment();
- 方法(3):
this.$store.state.count += 1;
直接修改 state 里面的值 ,但不会产生mutation的记录(不推荐)- 方法(4):在actions中调用mutations中改变状态的方法,然后在组件中可直接调用actions中的方法:
先在store中action 调用:increase(context){ context.commit(Increment,2); }
再在组件中调用:this.myIncrease()
- state 分模块管理之后 得写映射 (注意写法,此时是
state.app.变量名
)
...mapState({ count:state =>{ return state.app.count } })
<template>
<div id="app">
<h1>{{count}}</h1>
<h3>{{myCount}}</h3>
<button @click="increase">增加</button>
<button @click="decrease">减少</button>
<router-view/>
</div>
</template>
<script>
import {mapState} from "vuex";
import {mapGetters} from 'vuex';
import {mapMutations} from 'vuex';
import {mapActions} from 'vuex';
import {Increment,Decrement} from '@/store/mutation-types'
export default {
name: 'App',
computed:{
1.分类管理之前
...mapState(['count']), //展开数组
...mapGetters(['myCount']),
2.state 分模块管理之后 得写映射
...mapState({
count:state =>{
return state.app.count
}
})
},
methods:{
//...mapMutations(['increment','decrement']),
...mapMutations([Increment,Decrement]),
...mapActions(['myIncrease','myDecrease']),
increase(){
// this.$store.commit('increment');
// this.increment();
//直接修改 state 里面的值 不会产生mutation的记录
// this.$store.state.count += 1;
this.myIncrease({id:123}); // 可传参
},
decrease(){
// this.decrement();
this.myDecrease()
}
}
}
}
</script>
最后看下效果,也感受一下,全局状态管理的舒服感,始终要记得:** Vuex 的 store 中的状态的唯一方法是提交 mutation**,所以官方提供的浏览器插件Vue,就可清晰的记录每次mutation的结果。
每次加2,减少2,四次加,两次减
mutation记录了每次的操作
这就是最终的结果了,看视频学的,也看了一些官方文档,因为写项目的时候还没学这些,所以那些需要全局使用的信息,都存在了 localStorage中,这也是个方法,但是数据也不能存储太多,操作起来也不是太方便。
学了vuex也比较浅显,也没实际的在项目中使用过,也不太能体会它的优点,反而感觉有点繁琐,也许真正的使用了,才能体会到它的好处吧。
学无止境,苦海无涯!
今天的学习到此结束,下次不知道啥时候见了。