Vuex使用详解

本文详细介绍了Vuex在Vue.js应用程序中的作用,作为状态管理模式,它集中管理组件共享状态,确保状态变化的可预测性。文章通过实例展示了如何创建Vuex store,如何在组件中使用state、mutations、actions以及getters,强调了响应式状态管理和模块化的应用。还涵盖了Vuex的异步操作、模块化设计以及通过actions处理复杂逻辑。
摘要由CSDN通过智能技术生成

1. vuex基础

1.1 概念和作用解析
  • 官方解释: Vuex是一个专为Vue.js 应用程序开发的状态管理模式
    • 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
    • Vuex也集成到Vue 的官方调试工具devtools extension,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能
  • 状态管理到底是什么?
    • 状态管理模式、集中式存储管理这些名词听起来就非常高大上,让人捉摸不透。
    • 其实,你可以简单的将其看成把需要多个组件共享的变量全部存储在一个对象里面。
    • 然后,将这个对象放在顶层的Vue实例中,让其他组件可以使用。
    • 那么,多个组件是不是就可以共享这个对象中的所有变量属性了呢?
  • 如果是这样的话,为什么官方还要专门出一个插件Vuex呢?难道我们不能自己封装一个对象来管理吗?
    • 当然可以,只是我们要先想想VueJS带给我们最大的便利是什么呢?没错,就是响应式。
    • 如果你自己封装实现一个对象能不能保证它里面所有的属性做到响应式呢?当然也可以,只是自己封装可能稍微麻烦一些。
    • 不用怀疑,Vuex就是为了提供这样一个在多个组件间共享状态的插件,用它就可以了。
1.2 管理什么状态呢
  • 但是,有什么状态时需要我们在多个组件间共享的呢?
    • 如果你做过大型开放,你一定遇到过多个状态,在多个界面间的共享问题。
    • 比如用户的登录状态、用户名称、头像、地理位置信息等等。
    • 比如商品的收藏、购物车中的物品等等。
    • 这些状态信息,我们都可以放在统一的地方,对它进行保存和管理,而且它们还是响应式的(待会儿我们就可以看到代码了,莫着急)

2. vuex的配置

  • src下新建文件夹store并创建一个store.js文件

  • store.js

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    const store = new Vuex.Store({
        // 常用属性
        state:{},
        mutations:{},
        actions:{}
    });
    
    // 导出store
    export default store
    
  • main.js中引入

    import store from './store/store'
    
    /* eslint-disable no-new */
    new Vue({
      render: h => h(App),
      store
    }).$mount('#app')
    

3. vuex实现状态管理

3.1 Vuex状态管理图例

在这里插入图片描述

3.2 多界面的状态管理
3.2.1 案例

如图所示上下两个部分是不同组件显示的内容,我们要实现点击加减按钮,上下两个数字都会改变,实际上这两个数字是由共享变量counter决定的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bAKagvnL-1631155615164)(C:\Users\xmydd\AppData\Roaming\Typora\typora-user-images\image-20210907170533216.png)]

  • 上面这个案例我们可以通过父子组件通信实现
  • 但是当两个组件不存在父子关系时,我们需要用Vuex来实现
3.2.2 实现步骤

实现思路

  1. 提取出一个公共的store对象,用于保存在多个组件中共享
    的状态
  2. 将store对象放置在new Vue对象中,这样可以保证在所有
    的组件中都可以使用到
  3. 在其他组件中使用store对象中保存的状态即可
    • 通过this.$store.state.属性的方式来访问状态
    • 通过this.$store.commit('mutation中方法')来修改状态
  4. 注意事项:
    • 我们通过提交mutation的方式,而非直接改变
      store.state.count
    • 这是因为Vuex可以更明确的追踪状态的变化,所以不要直接
      改变store.state.count的值。

代码

  • store.js
const store = new Vuex.Store({
    state:{
        counter: 100,
    },
    mutations:{
        increment(state){
            state.counter++;
        },
        decrement(state){
            state.counter--;
        }
    },
});
  • Home.vue
<template>
    <div id="home">
        <p>-------------------------</p>
        <h2>{{$store.state.counter}}</h2>
    </div>
</template>
  • App.vue
<template>
  <div id="app">
    <h2>{{$store.state.counter}}</h2>
    <button @click="addtion">+</button>
    <button @click="subtraction">-</button>

    <home></home>
  </div>
</template>
methods:{
    addtion(){
        this.$store.commit('increment');
    },
    subtraction(){
        this.$store.commit('decrement');
    }
},

4. vuex - getters的使用

当我们需要从store中获取一些state变异后的状态,比如需要对数组进行筛选。虽然可以通过计算属性computer在用filter进行筛选,但是当另一个组件也想这样的话,代码就会显得繁琐。这时我们可以使用getters

前提:

state:{
    students:[
        {id:1, name:'lili', age: 18},
        {id:2, name:'amy', age: 15},
        {id:3, name:'daming', age: 28},
        {id:4, name:'lisi', age: 21},
    ]
},
  • students数组进行筛选,选出age大于20的

    getters:{
        getAge(state){
            return state.students.filter(s => s.age > 20);
        }, 
    },
    
    • 使用

      <h2>获取年龄大于20的数组</h2>
      <p>{{$store.getters.getAge}}</p>
      
  • getAge的数组长度

    • 这时需要用到getters里的getAge,那么就要把getters作为参数传进去
    • getters里面的方法第一个参数是state;第二个参数就是getters,就算第二个参数你起了一个别的名字,他也是表示getters;没有第三个
    getters:{
        getLength(state, getters){
            return getters.getAge.length
        },
    },
    
    • 使用

      <h2>获取年龄大于20的数组长度</h2>
      <p>{{$store.getters.getLength}}</p>
      
  • 从组建中传一个参数过来,获取年龄大于10的数组

    • 获取组件传过来的参数,就要返回一个带参数的函数
    getters:{
        getAgeStu(state){
            // return function(age){
            //     return state.students.filter(s => s.age > age);
            // }
    
            return age => {
                return state.students.filter(s => s.age > age);
            }
        }
    },
    
    • 使用

      <h2>获取年龄大于10的数组</h2>
      <p>{{$store.getters.getAgeStu(10)}}</p>
      

5. vuex - mutation

5.1 vuex - mutation传递参数
  • 在通过mutation更新数据的时候,有可能我们希望携带一些额外的参数
    • 参数被称为是mutation的载荷(Payload)
5.1.1 传递单个参数
  • 传递一个参数给store,点击+5按钮数字加5,也可以传递10,让他+10
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5zXIQXcQ-1631155615168)(C:\Users\xmydd\AppData\Roaming\Typora\typora-user-images\image-20210908102457035.png)]
  • App.vue
<template>
  <div id="app">
    <h2>{{$store.state.counter}}</h2>
    <button @click="addCounter(5)">5+</button>
  </div>
</template>
methods:{
    addCounter(count){
      this.$store.commit('addCounter', count);
    }
},
  • store.js
mutations:{
    addCounter(state,count){
        state.counter += count;
    }
},
5.1.2传递对象

store里的students添加元素

  • App.vue
<button @click="addNewArg">添加学生</button>
addNewArg(){
    const obj = {id:5, name:'张强', age: 68};
    this.$store.commit('addNewArg', obj);
}
  • store.js
mutations:{
    addNewArg(state,obj){
        state.students.push(obj);
    }
},
5.2. vuex - mutation提交方式补充
  • 以对象的形式提交

App.vue

addCounter(count){
    // this.$store.commit('addCounter', count);

    this.$store.commit({
        type: 'addCounter',
        count
    })
},

store.js

addCounter(state,payload){
    state.counter += payload.count;
    //console.log(payload);
},
  • 打印一下传过来的参数payload

    • 并不只是count,他包含了counttype
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iJ6SIsxm-1631155615173)(C:\Users\xmydd\AppData\Roaming\Typora\typora-user-images\image-20210908112922513.png)]
5.3 vuex - mutation的类型常量

在组件中使用mutation中的方法时,需要来回复制,有的人还会手写,这样很容易出错
在这里插入图片描述

  • 官方推荐我们把函数名定义为一个常量

  • 新建一个文件mutations.types.js文件

    export const INCREMENT = 'increment'
    
  • 在组件和store.js中进行更改

    • 组件中
    // 引入文件
    import {INCREMENT} from './store/mutations-types'
    
    methods:{
        addtion(){
            this.$store.commit(INCREMENT);
        },
    },
    
    • store.js
    // 引入文件 
    import {INCREMENT} from './store/mutations-types'
    
    mutations:{
    	[INCREMENT](state){
         	state.counter++;
     	},   
    }
    

6. vuex - actions

6.1 actions的基本定义
  • actions的功能跟mutation基本相同,不同的是actions一般用来代替mutation实现异步操作

  • mutation中也可以实现异步操作,但是我们一般不在mutation中写异步函数

  • actions里函数参数为context

    actions:{
        actionInfo(context, payload){
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    context.commit('updateInfo');
    
                    console.log(payload);
    
                    resolve('111');
                }, 1000)
            })
        }
    }
    

7. vuex - modules

  • 在大型项目中,如果把所有需要共享的数据都存放在state中,就会显得非常的臃肿
  • vuex为我们提供了modules属性,我们可以定义很多不同的模块,每个模块里都有自己的state、actions、mutations等等
const moduleA = {
    state:{
        name: '闫刚'
    },
    mutations:{
        changeName(state){
            state.name = "李想";
        }
    },
    actions:{},
    getters:{}
}

const store = new Vuex.Store({
    modules:{
        a: modulesA
    }
})
7.1 使用详解
  • 引用state里的属性

    <p>{{$store.state.a.name}}</p>
    
    • 通过devtools我们可以查看到,根store下的state里包含了我们在modules里定义的模块a
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fKCwi8kE-1631155615180)(C:\Users\xmydd\AppData\Roaming\Typora\typora-user-images\image-20210908214308799.png)]
    • 所有想使用a里的state,直接$store.state.a.属性名
  • mutation

    <button @click="changeName">更改name</button>
    
    changeName(){
        this.$store.commit('changeName');
    }
    
    • mutations的使用方法同根store里的一样
    • 系统在识别到这个方法时会先查看根store里的mutations是否有同名的,没有的话再去模块中找。所以起函数名不要起一样的
  • getters

    • getters的使用方法跟根store里的一样
    • 方法参数也一样,不同的是,模块里的可以通过参数rootState引用根state里的属性
    <p>{{$store.getters.fullName}}</p>
    <p>{{$store.getters.fullName2}}</p>
    <p>{{$store.getters.fullName3}}</p>
    
    getters:{
        fullName(state){
            return state.name += '1111';
        },
        fullName2(state, getters){
            return getters.fullName + '222';
        },
        fullName3(state, getters, rootState){
            return getters.fullName + rootState.counter;
        }
    }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DgqQAlrr-1631155615181)(C:\Users\xmydd\AppData\Roaming\Typora\typora-user-images\image-20210909102230967.png)]

  • 通过devtools,我们可以发现,模块a里定义的getteras,被放到了根getters
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YyUwpVp5-1631155615184)(C:\Users\xmydd\AppData\Roaming\Typora\typora-user-images\image-20210909102408200.png)]

  • actions

    • 使用方法跟根actions里的一样,不同的是模块里的actions方法参数context包含的内容不同
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lkipZdJi-1631155615186)(C:\Users\xmydd\AppData\Roaming\Typora\typora-user-images\image-20210909104305362.png)]
    • 当我们需要使用根节点下的属性方法时,可以调用context.rootGetters
    actions:{
        updateName(context){
            //console.log(context);
            setTimeout(() => {
                context.commit('changeName', '明明');
            },1000);
        }
    },
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值