一、vuex是做什么的?
官方解释: Vuex是一个专为Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
1、何为状态管理?
可以简单的将其看成把需要多个组件共享的变量全部存储在一个对象里面。然后,将这个对象放在顶层的Vue实例中,让其他组件可以使用。
2、如果是共享变量的话为什么不能自己封装一个对象来管理呢?
vueJS带给我们最大的便利就是响应式。Vuex就是为了提供这样一个在多个组件间共享状态的插件。
3、能够管理什么状态呢?
例如:用户的登录状态、用户名称、头像、地理位置信息等等,商品的收藏,购物车中的商品等等。
二、安装vuex
npm install vuex --save
三、调用插件vuex
在与App.vue同级目录下创建一个store文件夹,在文件夹内创建一个index.js文件。在文件中写入:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
然后在main.js中引入:
import store from './store'
//记得要挂载到响应组件上
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
四、介绍state内的index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
counter:0
},
mutations: {
increment(state){
state.counter++;
}
},
actions: {
},
modules: {
}
});
export default store
在外部组件引用
<h2>{{$store.state.counter}}</h2>
<!-- 不建议,原因如下: -->
为什么不选择直接在$store去修改state里面的状态?
因为如果直接使用的话,当多个组件同时修改$store时我们没法跟踪每次修改的值变化是由于哪次操作引起的,所以我们需要借助一个devtools去记录。
①mutations
vuex的store状态更新的唯一方式:提交mutation
1、里面存放一些全局的方法,例如:
const store = new Vuex.Store({
state: {
counter:0
},
mutations: {
increment(state){ //increment叫做事件类型
state.counter++;
}
},
actions: {
},
modules: {
}
});
2、在其他组件中试图修改state中couter的值
<button @click="addition">+1</button>
methods:{
//有关store的调用
addition(){
this.$store.commit('increment');//对应mutations中的方法名字
}
}
3、查看devtools中的状态改变过程
4、传参
如果传递多个参数的话,则可以传递一个对象
methods:{
//一个参数
addcount(count){
this.$store.commit('incrementCount',count);//对应mutations中的方法名字
}
//多个参数
addstu(){
const stu = {id:14,name:'小花'};
this.$store.commit('incrementStu',stu);//对应mutations中的方法名字
}
}
mutations: {
//一个参数传变量
incrementCount(state,counter){ //increment叫做事件类型
state.counter+=counter;
},
//多个参数传对象
incrementStu(state,stu){
state.students.push(stu);
},
},
5、提交风格
以上都是普通的提交风格,vuex还提供了另外一种提交风格,它是一个包含了type类型的
addcount(count){
this.$store.commit(
type:'incrementCount',
count,
);//对应mutations中的方法名字
}
incrementCount(state,payload){ //increment叫做事件类型
state.counter+=payload.count;
},
6、响应式
后加入的数据不在响应式系统里,即便是数组加入进去了也无法及时显示。
解决办法:
updateInfo(state){
state.info['address'] = '洛杉矶'; //不是响应式
Vue.set(state.info,'address),'洛杉矶'); //是响应式
delete state.info.age; //不是响应式
Vue.delete(state.info,'age'); //是响应式
}
7、常量类型
这个点目前尚未完全理解玄妙之处,留个坑以后记录。
8、同步函数
通常情况下,Vuex要求我们Mutation中的方法必须是同步方法。
主要的原因是当我们使用devtools时,可以devtools可以帮助我们捕捉mutation的快照.但是如果是异步操作,那么devtools将不能很好的追踪这个操作什么时候会被完成。如果一定要异步,就使用action
②getters
如果页面上显示的state里的内容需要进行计算的加成,为了方便以防每个页面都设置computed属性我没可以直接在vuex中设置getters,类似于computed中的定义,然后在vue中引用。
1、设置getter里的内容
getters:{
powercounter(state){
return state.counter*state.counter;
}
},
2、引用
<h2>
{{$store.getters.powercounter}}
{{$store.getters.more20stu(20)}}
</h2>
3、getters传参
PS:函数第一个参数默认是state,第二个参数是getters,如果要人为传递参数不能将变量直接设置为第三个参数,因为规定不允许。所以我没可以选择return一个函数,不和曾经一样在函数内获取属性得到结果,而是通过函数去调用这个返回的函数,这样就可以传递参数了。(这种方式返回函数会在每次调用时触发函数,不会有缓存结果)
getters:{
more20stu(state){
return state.student.filter(s=>s.age>20)
},
more20stuLength(state,getters){
return getters.more20stu.length;
}
},
getters:{
more20stu(state){
return function(age){
return state.students.filter(s=>s.age>age)
}
},
more20stuLength(state,getters){
return getters.more20stu.length;
}
},
③actions
Action类似于Mutation,但是是用来代替Mutation进行异步操作的。(action相当于一个中介)
1、普通使用方法
updateInfofromvue(){
this.$store.dispatch('aupdateInfo','我是payload');
}
mutations: {
updateInfo(state){
state.info.name = '11';
}
},
actions: {
//context,上下文
aupdateInfo(context,payload){
setTimeout(()=>{
context.commit('updateInfo');
},1000)
}
},
2、如何通知上一层修改成功?
updateInfofromvue(){
this.$store.dispatch('aupdateInfo',{
message:'我是携带的信息',
success:()=>{
console.log('里面已经完成了’);
}
});
}
actions: {
//context,上下文
aupdateInfo(context,payload){
setTimeout(()=>{
context.commit('updateInfo');
console.log(payload.message);
payload.success();
},1000)
}
},
3、上一级通知高级用法promise(留坑后补)
updateInfofromvue(){
this.$store.dispatch('aupdateInfo','我是携带的信息)
.then(res=>{
console.log(res);
})
;
}
actions: {
//context,上下文
aupdateInfo(context,payload){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
context.commit('updateInfo');
console.log(payload);
resolve('1111');
},1000)
})
}
},
④modules
Module是模块的意思,为什么在Vuex中我们要使用模块呢?Vue使用单—状态树,那么也意味着很多状态都会交给Vuex来管理。当应用变得非常复杂时,store对象就有可能变得相当臃肿。
为了解决这个问题, Vuex允许我们将store分割成模块,
(Module),而每个模块拥有自己的states、mutations、actions、getters等。
1、store定义
const moduleA = {
state:{
name:'222',
},
mutations:{}, //和之前一样使用,就是名字最好不要重复
actions:{},
getters:{},//也是一样使用,名字不重复
//其中getters里可以这样用 fullnames(state,getters,rootState){
// return getters.fullname2+rootState.counter
// }
}
}
const store = new Vuex.Store({
state: {
counter:0
},
mutations: {
increment(state){
state.counter++;
},
},
modules: {
a:moduleA,
}
});
2、调用(相当于modules里的模块放入了state)
<h2>
{{$store.state.a}}
</h2>
⑤state
state单一状态树
如果你的状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难。所以Vuex也使用了单—状态树来管理应用层级的全部状态。
单一状态树能够让我们最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便的管理和维护。