• Vue的仓库vuex


    Vue.js是一个渐进式的框架,是一个分层的设计模式。一共分为五层,核心库为基础,在这基础上添加组件系统、客户端路由、大规模状态管理和开发环境。

    其中大数据状态管理对应的技术就是vuex,它是由Vue框架开发团队提供的一个插件。

    仓库vuex的作用:

    能够在vuex中集中管理共享的数据,易于开发和后期维护;

    能够高效地实现组件之间的数据共享, 提高开发效率;

    存储在 vuex中的数据都是响应式的,能够实时保持数据与页面的同步。

    学习使用这个功能之前,我们先看一下它的结构:

     可以看到vuex在图中由Actions、Mutaitions、State组成,与组件实例化构成一个循环。

    其中State为状态其实就是存放的数据;actions直译为行为,就是一个会对数据修改的一个异步行为,可以理解为是一个中转站;Mutaitions中是对数据真正的操作。

    引入vuex

    第一种方式:通过CDN引入

    第二种方式:npm i vuex -save下载包再进行配置

    在main.js中配置:

    1. //导入:
    2. import Vuex from "vuex"
    3. Vue.use(Vuex)
    4. //创建仓库
    5. const store=new Vuex.Store({
    6. //配置state、actions、mutaitions等
    7. })
    8. //挂载到vm对象
    9. new Vue({
    10. render(h){return h(app)},
    11. router,
    12. store//挂载以后 所有的组件就可以直接从store中获取全局数据
    13. }).$mount( "#app")

    第三种方式:vue cli脚手架自己配置,在vue create "项目名"时,选择上vuex,脚手架会自动帮我们创建成功。

    具体来学习vuex的配置项

    1、state状态 

    就是我们共享数据的存放位置,就与data书写形式一样,如:

    1. var store=new Vuex.Store({
    2. state: {
    3. msg:"仓库中的数据",
    4. arr:[{id:001,name:"zs"},{id:002,name:"ls"}],
    5. obj:{a:1}
    6. },

    在组件中获取数据时,如获取msg为例,通过this.$store.state.msg。

    这里的this.$store,是在引入时通过Vue.use(Vuex)时给Vue对象原型上绑定了的对象,所有组件中都可以使用。

    2、getter

    它就好比我们学过的计算属性,每个方法内都会传入state,可以操作state内的数据。

    例如:返回state中两个数的和

    1. var store=new Vuex.Store({
    2. state: {
    3. a:1,
    4. b:2
    5. },
    6. getters:{
    7. sum(state){
    8. return state.a+state.b
    9. }
    10. }
    11. })

     获取sum:this.$store.getters.sum

    3、Mutaitions

    这个配置用于修改state中的数据,官方文档中它是在同步代码中实现,但是我们自己测试的时候在里面写异步代码也能实现。

    还有,官方文档中说它是更改 Vuex 的 store 中的状态(数据)的唯一方法,不要用赋值表达式直接在组件中给store设置新数据,但是直接赋值效果也能够实现。

    组件中修改state的数据,需要用到$store一个方法commit(),它的作用是传递参数并触发mutaition里对应的方法(专业说法为提交负荷)。

    commit()的传参

    1、普通形式:commit("name",d),这里的name为mutaitions中配置的方法名,d为我们传递的参数,可以是数字、数组、对象等。

    2、以对象形式传入:commit({type:"name",d:dd}),把整个对象作为了第二个参数传入mutations,type对应的就是mutaitions中配置的方法名。

    mutaitions里面的配置:

    1. mutations: {
    2. name(state,arg){
    3. //业务
    4. },

    name为方法名,第一个参数是传入的state,第二个参数就是commit传来的参数。

    完整实现一下:在box组件中修改state中的值

    box.vue:

    1. mounted(){
    2. this.$store.commit("change",11)
    3. }

    store下的index.js:

    1. import Vue from 'vue'
    2. import Vuex from 'vuex'
    3. Vue.use(Vuex)//让组件的原型链中 有仓库的工具代码
    4. export default new Vuex.Store({
    5. state: {
    6. num:1
    7. },
    8. mutations: {
    9. change(state,arg){
    10. state.num=arg
    11. }
    12. },
    13. })

    程序一运行,state中的num由1就变成了11.

    4、Action

    Action 可以包含任意异步操作,它的作用就像一个中转站,当修改的state的代码不是异步的或者是没有什么逻辑判断,我们直接在组件中commit操作Mutaitions;但是当存在异步操作或者很多逻辑判断时,我们一般就要加上Action这一步,组件中先将数据传递给Action,Action处理后再传给Mutaitions。

    组件中传递信息给Action需要用到$store上的dispacth方法,它的传参跟commit传参形式是一样的,一种是普通形式,一种是对象形式。

    actions中的配置是方法传来的两个参数,第一个不再是state,而是一个上下文对象,是一个简化了的store对象;第二个参数为组件中传递的数据。

    流程非常简单,就是:组件——>Action——>Mutaition

    代码展示:

    组件中:

    1. mounted(){
    2. this.$store.dispatch("change",11)
    3. }

    actions和mutaitions中:

    1. import Vue from 'vue'
    2. import Vuex from 'vuex'
    3. Vue.use(Vuex)//让组件的原型链中 有仓库的工具代码
    4. export default new Vuex.Store({
    5. state: {
    6. num:1
    7. },
    8. actions:{
    9. change(context,arg1){
    10. //异步处理
    11. setTimeout(()=>{
    12. context.commit("change1",arg1)
    13. })
    14. }
    15. },
    16. mutations: {
    17. change1(state,arg2){
    18. state.num=arg2
    19. }
    20. },
    21. })

    5、Module

    可用于业务分块开发: 由于使用单一状态树,应用的所有状态(数据)会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。 为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter

    具体使用:

    分块做业务时,一个对应一个store这样不容易混乱,而且模块化开发更容易维护。

    一个人对应一个js文件,在里面配置自己的 state、mutation、action、getter,然后导入导出到index.js文件中,放到modules配置项中。

    如:自己的js文件

    1. export default {
    2. namespaced: true,//局部命名空间(让state的中变量与其他模块中的同名变量不冲突)
    3. state: {
    4. msg:"张三的公共数据"
    5. },
    6. getters: {
    7. ...
    8. },
    9. mutations: {
    10. ....
    11. },
    12. actions: {
    13. ...
    14. }
    15. }

    index.js中引入:

    1. import Vue from 'vue'
    2. import Vuex from 'vuex'
    3. import Model1 from "./Model1.js"
    4. Vue.use(Vuex) //让组件的原型链中 有仓库的工具代码
    5. export default new Vuex.Store({
    6. state: {
    7. },
    8. getters: {
    9. },
    10. mutations: {
    11. },
    12. actions: {
    13. },
    14. modules: {
    15. Model1,
    16. }
    17. })

    使用时,某个组件要使用Model1中的公共数据:this.$store.state.Model1.msg;

    要使用Model1中motaitions配置的方法:this.$store.commit("Model1/change",num);

    使用getters:this.$store.getters["Model1/x"];

    使用dispatch:this.$store.dispatch("Model1/change",num)

    mapState,mapGetters,mapMutation,mapAction的使用

    mapState

    最后介绍一种编写代码的优化,在组件使用state数据时,我们需要this.$store.state.n才能取到数据,当要取大量数据时,this.$store.state都是重复的操作,因此官方给我们了一个mapState方法来优化,借助它来生成计算属性。

    要使用首先在组件中,引入这个mapState,如:import {mapState} from 'vuex'

    mapState()方法可以传入数组或者对象。

    传入对象时:mapState({a:"aa",b:"bb"}),其中a,b为生成的属性名,"aa"和"bb"就是this.$store.state.aa和this.$store.state.bb。

    等同于:

    computed:{

            a(){

                    return this.$store.state.aa

            }

    }

    这样就可以看出,框架利用mapState将state中数据帮我们生成了计算属性。这个时候我们要使用this.$store.state.aa时,直接使用a就行了,是不是极大的减少了代码量。

    传入数组时,更为简洁:mapState(["aa","bb"]),这样的意思就是让计算属性名与state中的属性名相同。等同于对象写法:mapState({aa:"aa",bb:"bb"})。

    注意:属性值加引号

    mapState(["aa","bb"])运行后,aa就可以取出this.$store.state.aa。

    写出代码:

    1. import {mapState} from "vuex"
    2. export default{
    3. computed:{
    4. ...mapState(["aa","bb"]),
    5. ...mapState({a:"aa",b:"bb"}),//不想计算属性与state数据同名时用
    6. }
    7. }

    注意这里mapState前面要加...,这是拓展运算符。因为mapState的返回值是一个对象,需要把它拆开成每一项,形成键值对的形式,否则会报错。

    mapGetters

    用法与mapState相同,通过mapGetters将它的数据转换为组件的计算属性。两个方法只是名字不同,用法全都相同,故不在详细说明。

    mapMutations

    前面两个方法是转换为计算属性,优化简写this.$store.state和this.$store.getters

    很明显看到mapMutations,我们应该就已经猜到了它的用法。即,优化简写this.$store.commit()

    同样它传入的参数也有两种形式:对象和数组

    对象写法:mapMutations({a:"a1",b:"b1"}),

    等同于:

      methods: {

          a(value){

            this.$store.commit("a1",value)

          },

           b(value){

            this.$store.commit("b1",value)

          },

        },

    细心的同学可以看到,这里的生成的方法需要传参。这里已经生成了a和b方法,在实际使用的时候我们手动给它传一个参数,

    如:当点击按钮时,将10传到mutaitons配置的a1方法中