Vuex笔记

Vuex

概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件对于Vue应用中多个组件的共享状

态进行集中式管理的读写操作也是一种组件之间通信的方式,且适用于任意组件之间的通信。

Vuex使用的时机

  1. 多个组件之间依赖于同一个状态
  2. 来自不同的组件的行为需要变更同一个状态

全局事件总线处理共享数据:需要先创建一个全局事件总线,各个组件之间需要对数据实现事件监听,但是这种方法一旦随着组件多起来,则关系线就会很乱。

 Vuex的数据共享:利用vuex技术,将共享的数据放到vuex插件中,各个组件之间如果想调用该方法就使用提供的方法即可,每一个组件之间传递数据关系线条理清晰。

使用vuex的特点是:数据放到vuex中保管,该数据就成为了共享数据,一个组件修改了该数据,则其他组件用到该数据的地方也会改变。

Vuex原理图

 其中所有的组件实例对象都可以方法vuex管理的数据,一个完整的vuex至少包含了三个部分:Actions,Mutations,State,这些部分由一个store管理,store提供的函数如dispatch,commit等。当一个组件实例对象想修改某一个共享的数据的时候,会调用dispatch(执行操作(如add),数据)去是就进入到Actions中。

  1. Actions:本质是一个对象,当组件实例对象,在Actions中存放这若干个数据,其中必定有一条属性和刚才dispatch传递过来的执行操作名一模一样add,并且该属性接收一个函数作为参数,并且将刚才的dispatch传递过来的数据接收到。并且在函数的最后,需要手动调用commit方法,将该数据继续传递给Mutations。有的时候传递的是一个具体的值,可以直接在组件实例对象中调用commit方法进入Mutations。如果在dispatch中数据并没有给出,而是需要通过ajax请求获取的,这个时候就必须进入Actions中处理。由此才允许进入Mutations。在Actions中设计第一个参数为一个上下文参数context,使其每一个函数都具有dispatch,state等属性,而不是直接将commit作为参数。目的是为了解决如果一个actinos中某个函数处理逻辑及其繁琐,可以将一个函数功能分成多个函数,在函数中使用dispatch实现串联,并且在最后一个函数中将处理完成的逻辑使用commit方法提交给mutations处理。注意:虽然在这一步可以进行对state中的数据进行处理也能正确的进行响应。但是vuex的开发者工具不会提供任何信息帮助我们分析,开发者工具只负责mutations
  2. Mutations:本质是一个对象,该对象存在一个State中的数据,该对象也存在一个属性和dispatch中的操作名一模一样的属性add,并且也是以函数作为值,函数接收传递来的数据并修改,在Mutations中,执行具体的操作,并且vuex会帮助我们自动去执行mutate方法去修改state中的数据。在mutations中,vue和vuex共用一个开发者工具,vuex中的开发者工具只负责mutations中的操作,并对每一次操作进行汇报。
  3. State:本质是一个对象,存放这所有需要共享的数据源,并且最后会执行render函数重新解析页面。vuex为State中的所有数据添加了数据代理

安装Vuex环境

在Vue2中需要安装vuex3版本

在Vue3中需要安装vuex4版本

配置vuex环境中的store

需要配置一个store属性,所有的vm和vc实例对象都可以访问到该属性,并且store配置项只有当配置了vuex环境后,vue才会认为store属性是配置项属性,所有的vm和vc才真正的拥有这些属性。如果不添加vuex环境,则无法配置store配置项,在vm和vc身上就没$store属性

 通过将配置store的具体代码单独封装在一个文件中,以下是vue推荐的创建模式,在index文件中写入具体的实现

 

在index文件中创建如下代码,即配置store所需的配置项

引入vuex,调用该构造函数,即需要new Vuex,new完之后需要去调用该构造函数身上的Store属性配置

调用Vuex.store({})创建vuex环境中store的配置对象

// 引入vuex
import Vuex from 'vuex'

// 配置store需要的三个对象:actions,mutations,state
const actions = {}
const mutations = {}
const state = {}

// 需要使用初始化操作,设置配置项,类似vue的实例化操作
// 导出接口
export default new Vuex.Store({
  actions,
  mutations,
  state
})

但是在引入store配置的内容后,在vm配置对象中配置store后控制台给出报错提示。提示说明了Vue.use(Vuex)必须在创建一个store实例之前就存在

 注意:在脚手架中,会默认将所有的import语句进行提升,所以如下办法是没法实现效果的

 所以解决此问题的办法就是在store文件中的index文件下先使用Vue.use(Vuex),这样子在导入import文件的时候就会先解析Vue.use(Vuex),后执行store的实例化操作

 当按照如上步骤配置完成后,所以的vm和vc组件实例对象身上都成功的配置$store属性

开始调用vc身上$store提供的dispatch方法

当在dispatch中设置了操作的方法add,必须在actions中配置对应的add属性,其参数为函数,该函数接收两个参数,其中第一个参数为一个迷你的store具有store的相关属性,第二个参数为传递来的真实数据,所以可以在actions中的方法中调用commit方法,将参数传递给下一个mutations

 

 在mutations中,第一个参数是State对象中的数据,并且进行了数据代理,所以才需要在mutations中修改共享数据,第二个数据为传递来的参数(通常在actions中将属性名小写,在mutations中将大写)

 

所有的逻辑都在actions中完成,在mutations中,只负责对state中的数据进行操作

  methods: {
    Add() {
      this.$store.dispatch("add", this.n);
    },
    Sub() {
      this.$store.dispatch("sub", this.n);
    },
    AddOdd() {
      this.$store.dispatch("addOdd", this.n);
    },
    AddWait() {
      this.$store.dispatch("addWait", this.n);
    },
  },
const actions = {
  add(context, y) {
    // console.log("actions", context, y)
    context.commit('ADD', y)
  },
  sub(context, value) {
    context.commit('SUB', value)
  },
  addOdd(context, value) {
    if (context.state.sum % 2) {
      context.commit('ADD', value)
    }
  },
  addWait(context, value) {
    setTimeout(() => {
      context.commit('ADD', value)
    }, 300)
  }
}
const mutations = {
  ADD(state, y) {
    console.log('mutation', state, y)
    state.sum += y
  },
  SUB(state, value) {
    state.sum -= value
  }
}
const state = { sum: 0 }

像这种进行普通的数值传递的时候,不进行ajax请求数据的时候,可以在前端不实用dispatch方法,直接使用commit方法将值传递给mutations

store中配置可选项getters

store中的getters,类似computed计算属性的,写法一样,都需要一个函数,并函数接收state作为参数,切函数需要返回值,vuex会使用函数名去接收这个return值。并且该数据会被配置数据代理。

以下是为store配置了getters配置项的代码,需要先设置getters中的代码逻辑,然后将该配置项交给store管理。

 如下是打印输出发现getter中的函数最终都如computed计算属性的结果,数据都进行了数据代理

 设计getters配置项的目的是是什么

当某一个地方需要使用到最终结果mutations处理的state中的数据,并且该数据需要被外部多次复用,这时候就需要使用到getters配置项了。如果使用computed计算属性则只能在一个组件内部进行复用,无法供外部使用复用。

并且getters中的数据,开发者工具也会帮助我们监测到。

在如下vue模板使用中,我们发现,我们总是去访问$store中的state属性或者getters属性,这就会导致我们的插值语法代码很长如下。虽然我们可以将如下代码使用计算属性简写,但是有没有什么办法可以帮助我们快速访问并生成对应的数据。为此我们引入了mapState方法和mapGetters方法。除此之外还有mapActions与mapMutations。

    <h1>这里显示的数据{{ $store.state.sum }}</h1>
    <h3>这里显示的数据变大了{{ $store.getters.bigSum }}</h3>
    <hr />
    <h2>{{ $store.state.subject }}</h2>
    <h2>{{ $store.state.address }}</h2>
  computed: {
    he() {
      return this.$store.state.sum;
    },
    xueke() {
      return this.$store.state.subject;
    },
    dizhi() {
      return this.$store.state.address;
    },
    qiuhe() {
      return this.$store.getters.bigSum;
    },
  },

mapState方法

用于快速映射state中的数据为计算属性使用

采用对象解构的方式引入vuex提供的mapState和mapGetters,这是必须执行的步骤

import { mapState, mapGetters } from "vuex";

结果打印测试看出了mapState和mapGetters都是函数,且都是接收两个参数

 使用mapState的方法

mapState方法需要传入一个对象,该对象中包含的每一个参数都不能随意瞎写。如下代码中的

he:"sum",即页面中所有求和的地方使用插值语法都使用{{he}},而"sum"是vue读取到这里就知道这需要从vuex中的state中读取,所以这里对应两个功能。并且最重要的是这个函数调用的返回值是一个对象,这才是决定可以在computed中使用的原因。在该返回值的对象中,可以发现刚才的dizhi,he等属性都被包装成函数的格式。这一步一一对应计算属性的函数式写法,所以只需要在计算属性中将该返回值对象展开...即可

第一种方法在mapState中传入对象作为参数

mapState({ he: "sum", xueke: "subject", dizhi: "address" })

 同时步骤对应第二种简写写法,但是这种写法是在mapState中传递数组作为参数。该方法也是返回一个对象,该对象格式如下图所示,也需要在计算属性中使用对象展开。

这种写法有两个功能,数组中的["sum",.....],会将sum作为计算属性中接收return的返回值,用于页面中的插值语法位置书写{{sum}},并且vue解析到这里就知道需要去store中的State中寻找sum属性。

mapState(["sum", "subject", "address"])

mapGetters方法

用于快速映射getter中的数据为计算属性使用

mapGetters方法的步骤和mapSta方法的步骤一样,具体代码如下

    ...mapGetters({ qiuhe: "bigSum" }),
    
    ...mapGetters(["bigSum"]),

引入下面两个mapMutations方法和mapActions方法是当methods方法出现如下情况,多次调用commit方法或者dispatch方法的情况下,vuex为我们提供了简便的写法,基本上和上面的几个写法一致

 依次从vuex中导入mapMutations和mapActions方法

mapMutations方法

作用:借助mapMutations方法快速生成methods中的方法,方法中会调用commit方法去联系mutations

当对该函数进行调用的时候输出如下。

该方法返回值也是一个对象,对象里的属性是函数,所以可以采用对象解构将属性提出来、

对象写法

 ...mapMutations({ Add: "ADD", Sub: "SUB" }),

Add方法是组件页面中调用的,ADD参数是给mutations去决定调用哪一个方法 

但是这最终页面显示如图所示,这是什么原因,为什么会打印一个对象

 通过在mutations中对方法中打印输出发现,ADD和SUB方法会自动接收一个参数,这个参数为事件对象,所以页面才会出现这种效果。

 在mapMutations中也是对commit方法的封装,而什么时候调用该方法是由页面点击事件去调用Sub或Add方法决定的。由于在组件中的回调函数没有指明获取的参数,且在调用commit方法的时候需要传递参数,于是vue就自动为我们处理,将默认参数传递给了mutations处理,即事件对象event,因此解决此办法就是在事件回调后面带上参数即可

 将回调函数改为如下就可以实现效果

 除了这种方法传递必要的数据还有一种方法,代码逻辑在注释中给出

 同理该写法也对应一个数组写法,这种写法的话页面中插值语法中也需要一一对应的调用

    ...mapMutations(["ADD", "SUB"]),

 mapActions方法

作用:借助mapActions方法快速生成dispatch方法与actions之间建立联系。

注意在点击事件中的回调函数中需要传递参数,否则默认传递一个事件对象作为参数

 下面这种是对象作为参数的写法

    // AddOdd() {
    //   this.$store.dispatch("addOdd", this.n);
    // },
    // AddWait() {
    //   this.$store.dispatch("addWait", this.n);
    // },

    ...mapActions({ AddOdd: "addOdd", AddWait: "addWait" }),

 下面是以数组作为参数

   ...mapActions(["addOdd", "addWait"]),

总结

mapState方法:用于帮助我们映射```state```中的数据为计算属性
computed: {
    //借助mapState生成计算属性:sum、school、subject(对象写法)
     ...mapState({sum:'sum',school:'school',subject:'subject'}),
         
    //借助mapState生成计算属性:sum、school、subject(数组写法)
    ...mapState(['sum','school','subject']),
},

mapGetters方法:用于帮助我们映射```getters```中的数据为计算属性
computed: {
    //借助mapGetters生成计算属性:bigSum(对象写法)
    ...mapGetters({bigSum:'bigSum'}),

    //借助mapGetters生成计算属性:bigSum(数组写法)
    ...mapGetters(['bigSum'])
},

mapActions方法:用于帮助我们生成与```actions```对话的方法,即:包含```$store.dispatch(xxx)```的函数
methods:{
    //靠mapActions生成:incrementOdd、incrementWait(对象形式)
    ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

    //靠mapActions生成:incrementOdd、incrementWait(数组形式)
    ...mapActions(['jiaOdd','jiaWait'])
}

mapMutations方法:用于帮助我们生成与```mutations```对话的方法,即:包含```$store.commit(xxx)```的函数
methods:{
    //靠mapActions生成:increment、decrement(对象形式)
    ...mapMutations({increment:'JIA',decrement:'JIAN'}),
    
    //靠mapMutations生成:JIA、JIAN(对象形式)
    ...mapMutations(['JIA','JIAN']),
}

 利用vuex实现多个组件之间数据的共享

当将store中的相关配置设置好的时候,其实组件之间的共享数据就已经完成了。

 Vuex中使用模块化开发

当有多个组件操作store的时候,将各自的数据存放在actions或mutations或state的时候,会让整个store显得很臃肿,如果多个组件不加分类的全部放入store的时候,维护起来是极其麻烦的。

如下代码,Count组件与Person组件的操作commit的方法全部放在mutations中,共享的数据全部放在state中。一旦数据多起来,后期就不容易维护。

分别为两个组件配置对应的store配置项

const Count = {
  actions: {
    Odd(context, value) {
      if (context.state.sum % 2) {
        context.commit('ADD', value)
      }
    },
    Wait(context, value) {
      setTimeout(() => {
        context.commit('ADD', value)
      }, 1000);
    }
  },
  mutations: {
    ADD(state, value) {
      state.sum += value
    },
    SUB(state, value) {
      state.sum -= value
    },
  },
  getters: {
    bigSum(state) {
      return state.sum * 10
    }
  },
  state: {
    sum: 0,
    name: 'Vue',
    address: '南京',
  }
}

const Person = {
  mutations: {
    ADD_PERSON(state, value) {
      // value为对象
      state.personList.unshift(value)
    }
  },
  state: {
    personList: [
      { id: nanoid(), name: '张三' },
      { id: nanoid(), name: '李四' },
    ]
  }
}

Store中配置modules配置项

当设置了modules配置项的时候,Vuex就会自动我们为多个组件之间配置的store

export default new vuex.Store({
  // 模块化配置项modules
  modules: {
    // 对象简写
    Count,
    Person
  }
})

配置完成后通过组件访问state中的数据,对应的输出如下,即最终模块化后的state中的数据都被收集到一个总的state对象中。

namespaced配置项属性:布尔值,作用是开启命名空间

当配置为modules的时候,页面中是无法实现效果的,所以需要在mapSta和mapGetters中配置第一个属性,即告诉该组件需要从哪一个模块中读取数据

 但是这样子依旧会报错:module模块化中缺少namesapced属性

 

const Count = {
  namespaced: true,
  actions: {
    Odd(context, value) {
      if (context.state.sum % 2) {
        context.commit('ADD', value)
      }
    },
    Wait(context, value) {
      setTimeout(() => {
        context.commit('ADD', value)
      }, 1000);
    }
  },
  mutations: {
    ADD(state, value) {
      state.sum += value
    },
    SUB(state, value) {
      state.sum -= value
    },
  },
  getters: {
    bigSum(state) {
      return state.sum * 10
    }
  },
  state: {
    sum: 0,
    name: 'Vue',
    address: '南京',
  }
}

const Person = {
  namespaced: true,
  mutations: {
    ADD_PERSON(state, value) {
      // value为对象
      state.personList.unshift(value)
    }
  },
  state: {
    personList: [
      { id: nanoid(), name: '张三' },
      { id: nanoid(), name: '李四' },
    ]
  }
}

那么如果使用函数的传统的方法,如何进行模块化的调用,对应的调用如下,最主要的就是如何区分是哪一个模块下的方法

注意打印store中getters中属性的书写格式,对应的可以采用该写法去调用,这种格式在getters中已经代表了哪一个模块下的某个属性。但是在对象的链式调用中不能使用'/'所以对应的使用对象调用的另一种格式,即数组的形式。

//方式一:自己直接读取
this.$store.state.personAbout.list
//方式二:借助mapState读取:
...mapState('countAbout',['sum','school','subject']),
//方式一:自己直接读取
this.$store.getters['personAbout/firstPersonName']
//方式二:借助mapGetters读取:
...mapGetters('countAbout',['bigSum'])
//方式一:自己直接dispatch
this.$store.dispatch('personAbout/addPersonWang',person)
//方式二:借助mapActions:
...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
//方式一:自己直接commit
this.$store.commit('personAbout/ADD_PERSON',person)
//方式二:借助mapMutations:
...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vuex Models是一个用于在Vue.js应用程序管理数据的库。它提供了一种模块化的管理模式,可以将store划分为多个模块(module),每个模块都有自己独立的state、mutation、action和getter。 使用Vuex Models非常简单。首先,您需要导入`genVuexModels`函数并使用它来生成存储字段。然后,在您的store配置,将这些存储字段放在`models`对象。例如,您可以在`store/index.js`文件进行配置,如下所示: ```javascript // your imports import { genVuexModels } from 'vuex-models' // Vue.use(Vuex), etc // First argument ... const models = genVuexModels({ a: { state: {}, mutation: {}, getters: {}, // ... }, // ... }) export default new Vuex.Store({ // ... models, // ... }) ``` 通过这样配置,您就可以在Vue组件轻松地访问和修改存储字段。例如,您可以使用`this.$models.a.state`来访问模块`a`的state,使用`this.$models.a.mutation`来提交模块`a`的mutation,使用`this.$models.a.getters`来获取模块`a`的getter。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [vuex-models:vue组件和vuex存储之间的简单双向数据绑定](https://download.csdn.net/download/weixin_42151305/16637681)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Vue学习笔记 —— Vuex之Models(模块化管理模式)](https://blog.csdn.net/weixin_43340295/article/details/110002537)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值