P15.3

阅读: 评论:0

P15.3

P15.3

P15.3-Vuex核心概念

文章目录

  • P15.3-Vuex核心概念
    • 1.概述
    • 2.State单一状态树
    • 3.Getters基本使用
      • 3.1.Getters基本使用案例
      • 3.2.Getters作为参数
      • 3.3.Getters传递参数
    • 4.Mutation
      • 4.1.Mutation传递参数
      • 4.2.Mutation传递多个参数
      • 4.3.Mutation对象方式传递参数
      • 4.4.Mutation响应规则
        • 4.4.1.方式一:修改在store中初始化好的属性,默认是响应式。
        • 4.4.2.方式二:set方式给state中的对象添加新属性
        • 4.4.3.方式三:用新对象给旧对象重新赋值
      • 4.5.Mutation常量
        • 4.5.1.为什么需要常量
        • 4.5.2.代码实现Mutation常量
        • 4.5.3.案例代码总结
    • 5.Action
      • 5.1.Action介绍
      • 5.2.Action异步操作
      • 5.3.Action异步操作结合Promise
      • 5.4.案例代码总结
    • 6.Module
      • 6.1.什么是Module
      • 6.2.Module创建模块并调用模块内容案例
      • 6.3.Mutation修改模块属性值案例
      • 修改模块属性值案例
      • 获取根store中的属性案例
    • 7.Actions
        • s和Actions案例完整代码
    • 8.项目结构
      • 8.1.Vuex结构化
        • 8.1.1.抽离state内容到单独的对象
        • 8.1.2.mutations内容抽离到mutations.js文件中
        • 8.1.3.actions内容抽离到actions.js文件中
        • 8.s内容抽离到getters.js文件中
        • 8.dules内容抽离到modules.js文件中
        • 8.1.6.index.js文件中导入所有模块
      • 8.2. Vuex结构化后完整代码
        • 8.2.1.store格式化后项目整体结构
        • 8.2.2.index.js格式化后完整代码
        • 8.2.3.mutation-types.js格式化后完整代码
        • 8.2.4.mutations.js格式化后完整代码
        • 8.2.5.actions.js格式化后完整代码
        • 8.s.js格式化后完整代码
        • 8.duleA.js格式化后完整代码
      • 8.3.预览格式化后效果

1.概述

前面的两篇文章介绍了Vuex是什么,简单使用Vuex。这篇文章详细介绍Vuex的核心概念。

2.State单一状态树

  • Vuex提出使用单一状态树, 什么是单一状态树呢?
    • 英文名称是Single Source of Truth,也可以翻译成单一数据源。
  • 但是,它是什么呢?我们来看一个生活中的例子。
    • OK,我用一个生活中的例子做一个简单的类比。
    • 我们知道,在国内我们有很多的信息需要被记录,比如上学时的个人档案,工作后的社保记录,公积金记录,结婚后的婚姻信息,以及其他相关的户口、医疗、文凭、房产记录等等(还有很多信息)。
    • 这些信息被分散在很多地方进行管理,有一天你需要办某个业务时(比如入户某个城市),你会发现你需要到各个对应的工作地点去打印、盖章各种资料信息,最后到一个地方提交证明你的信息无误。
    • 这种保存信息的方案,不仅仅低效,而且不方便管理,以及日后的维护也是一个庞大的工作(需要大量的各个部门的人力来维护,当然国家目前已经在完善我们的这个系统了)。
  • 这个和我们在应用开发中比较类似:
    • 如果你的状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难。
    • 所以Vuex也使用了单一状态树来管理应用层级的全部状态。
    • 单一状态树能够让我们最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便的管理和维护。

3.Getters基本使用

Getters是Vuex配置文件index.js 中重要的一个参数,他和组件的computer计算属性作用是一样的,都是用来将变量的值进行计算,然后返回该值给组件调用。

3.1.Getters基本使用案例

需求:

  • 在App组件中使用state保存students对象里年龄大于20的学生数据,配置Getters获取大于20岁的学生。App组件直接使用Getters计算后的数据。
  • 在index.js文件中配置getters过滤state的students对象数据
  • 在App组件中获取getters中more20stu属性计算结果
  • 预览数据只显示大于20岁的学生

3.2.Getters作为参数

需求:

  • 在上面的基础上,希望计算出符合条件学生的个数
  • 将getters对象作为参数传递到函数中,可以在函数中调用getters对象中的任意函数,获取该函数计算的结果。
  • 获取函数的结果,在此结果上进行计算可以减少重复代码。

  • 在App组件中获取getters中more20stuLength属性计算结果

3.3.Getters传递参数

需求:

  • 在第一次需求中我们是指定了获取20岁以上的学生,这个条件是限定死了,现在我们希望这个条件能够由用户来决定展示age大于多少岁的学生。
  • 1.Getters传递参数
  • 我们实现上面的需求,需要将条件设置为参数,由用户传递参数决定条件的值。
  • 但是getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数.
  • getters本身返回另一个函数.

  • getters本身返回另一个函数写法优化

  • App组件使用

  • 预览效果显示符合我们传入的age值结果

4.Mutation

  • Vuex的store状态的更新唯一方式:提交Mutation
  • Mutation主要包括两部分:
    • 字符串的事件类型(type)
    • 一个回调函数(handler),该回调函数的第一个参数就是state。

4.1.Mutation传递参数

需求:

  • 在Mutation修改counter值的时候,不希望没有都只增加一个数值,希望能够根据需要改变递增数值的大小,这个时候可以通过传递参数改变递增值的大小。

在通过mutation更新数据的时候, 有可能我们希望携带一些额外的参数
参数被称为是mutation的载荷(Payload)

  • mutation定义函数接收参数
  • App调用mutation传递参数改变counter值
  • 预览效果counter每次递增5

4.2.Mutation传递多个参数

需求:

  • 点击按钮添加一个学生信息,该学生信息封装成一个对象作为参数传递给Mutation的函数。

但是如果参数不是一个呢?

  • 比如我们有很多参数需要传递.

  • 这个时候, 我们通常会以对象的形式传递, 也就是payload是一个对象.

  • 这个时候可以再从对象中取出相关的信息.

  • Mutation定义函数接收对象类型参数

  • App组件调用Mutation函数添加一个学生信息

  • 预览添加学生信息

4.3.Mutation对象方式传递参数

在通过mutation更新数据的时候, 有可能我们希望携带一些额外的参数

  • 参数被称为是mutation的载荷(Payload)
  • Vue还提供了另外一种风格, 它是一个包含type属性的对象,Mutation中的>处理方式是将整个commit的对象作为payload使用。
  • 在index中接收组件传来的payload对象,通过payload对象获取对象中的属性值。
  • App组件将参数封装成payload对象传递

  • 接收App传入的对象,通过payload获取对象中的属性值

4.4.Mutation响应规则

Vuex的store中的state是响应式的, 当state中的数据发生改变时, Vue组件会自动更新.
这就要求我们必须遵守一些Vuex对应的规则:

  • 提前在store中初始化好所需的属性。(在state中定义的属性都是初始化好的属性,这些属性都是响应式的。当改变这些属性值的时候,通过监听者模式监听到改变值的属性,在界面自动刷新显示)
  • 当给state中的对象添加新属性时, 默认不是响应式。如果希望他们也变为响应式需要使用下面的方式向state添加属性:
    • 方式一: 使用Vue.set(obj, ‘newProp’, 123)
    • 方式二: 用新对象给旧对象重新赋值

下面通过案例介绍上面三种响应式修改数据方式

4.4.1.方式一:修改在store中初始化好的属性,默认是响应式。
  • 在index.js文件state中添加一个初始化的属性
  • 在index.js文件mutations添加updateInfo方法修改属性值
  • App组件调用updateInfo方法修改name属性
  • 预览修改已初始化的属性值是响应式
4.4.2.方式二:set方式给state中的对象添加新属性
  • index.js文件添加新的属性

  • App组件调用updateInfo方法传入属性值

  • 预览set方式响应式添加新属性

4.4.3.方式三:用新对象给旧对象重新赋值
  • index.js文件修改使用新的对象给info对象重新赋值
  • App组件调用updateInfo方法传入属性值
  • 预览新对象给旧对象重新赋值方式

4.5.Mutation常量

4.5.1.为什么需要常量

我们来考虑下面的问题:

  • 在mutation中, 我们定义了很多事件类型(也就是其中的方法名称).
  • 当我们的项目增大时, Vuex管理的状态越来越多, 需要更新状态的情况越来越多, 那么意味着Mutation中的方法越来越多.
  • 方法过多, 使用者需要花费大量的经历去记住这些方法, 甚至是多个文件间来回切换, 查看方法名称, 甚至如果不是复制的时候, 可能还会出现写错的情况.
    如何避免上述的问题呢?
  • 在各种Flux实现中, 一种很常见的方案就是使用常量替代Mutation事件的类型.
  • 我们可以将这些常量放在一个单独的文件中, 方便管理以及让整个app所有的事件类型一目了然.
    具体怎么做呢?
  • 我们可以创建一个文件: mutation-types.js, 并且在其中定义我们的常量.
    定义常量时, 我们可以使用ES2015中的风格, 使用一个常量来作为函数的名称.
4.5.2.代码实现Mutation常量
  • 1.新建一个JS文件管理Mutation常量

  • 2.在index.js文件中使用常量作为方法名称

  • 3.App组件调用UPDATE_INFO方法使用常量

  • 4.预览常量作为方法名称效果

4.5.3.案例代码总结

上面案例使用的代码,下面贴出是完整的代码。

  • index.js文件完整代码
import Vue from 'vue'
import Vuex from 'vuex'
import * as types from './mutation-types'// 1.安装插件
Vue.use(Vuex)// 2.创建Vuex对象,实际上我们创建的是Vuex模块中Store类的对象
const store = new Vuex.Store({// 保存状态state: {counter: 100,students: [{ id: 110, name: 'why', age: 18 },{ id: 111, name: 'kobe', age: 24 },{ id: 112, name: 'james', age: 30 },{ id: 113, name: 'curry', age: 10 }],info: {name: 'kobe',age: 40,height: 1.98}},mutations: {// 通过定义方法改变state对象中属性的值increment(state) {unter++},decrement(state) {unter--},incrementCount(state, payload) {unter += unt},addStudent(state, stu) {state.students.push(stu)},[types.UPDATE_INFO](state, payload) {// 修改已初始化的属性,是响应式//state.info.name = '科比'// 这样添加新的没有初始化的属性,结果不是响应式// state.info['address'] = payload.address// 第一种响应式方式Vue.set(对象, '新的属性名称', 属性值)添加新的属性// Vue.set(state.info, 'address', payload.address)// 第二种响应式方式用新对象给旧对象重新赋值state.info = {...state.info, 'address':payload.address}}},actions: {},getters: {// 定义一个属性more20stu获取函数返回值,这个原理和组件的comput一样more20stu(state) {// 获取年龄大于20岁的学生return state.students.filter(s => s.age > 20)},// 将getters对象作为参数传递到函数中more20stuLength(state, getters) {// 通过getters对象获取more20stu计算的结果,在这个结果上再次计算出数量。20stu.length},// getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数moreAgeStu(state) {// return function (age) {//   return state.students.filter(s => s.age > age)// }// 上面函数进行写法上优化使用箭头函数方式return age => {return state.students.filter(s => s.age > age)}}},modules: {}
})// 3.导出store对象
export default store 
  • App组件完整代码
<template><div id="app"><h2>{{ message }}</h2><!-- 使用Vuex插件store对象的state属性中的counter变量 --><h2>{{ $unter }}</h2><button @click="addtion">+</button><button @click="subtration">-</button><button @click="addCount(5)">+5</button><button @click="addStudent">添加学生</button><h2>----------App内容: info对象的内容是否是响应式----------</h2><h2>{{$store.state.info}}</h2><button @click="updateInfo('vue')">修改信息</button><h2>----------App内容: getters相关信息----------</h2><h2>{{$20stu}}</h2><!-- getters作为参数传递 --><h2>{{$20stuLength}}</h2><!-- getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数 --><h2>{{$AgeStu(12)}}</h2><!-- 使用HelloVuex组件模板 --><HelloVuex /></div>
</template><script>
import HelloVuex from "./components/HelloVuex";
import {UPDATE_INFO} from "./store/mutation-types"export default {name: "App",components: {HelloVuex,},data() {return {message: "我是App组件",};},methods: {addtion() {// 调用commit方法传入的参数就是我们index.js中mutations中定义的方法名称this.$storemit('increment');},subtration() {this.$storemit('decrement');},addCount(count) {// 普通的提交方式// this.$storemit('incrementCount',count);//payload提交参数风格,将传递的多个参数封装成对象传递this.$storemit({type: 'incrementCount',count})},addStudent() {const stu = {id:1, name: 'lina', age: 20}this.$storemit('addStudent', stu)},updateInfo(address) {this.$storemit({type: UPDATE_INFO,address})}},
};
</script><style>
</style>

5.Action

5.1.Action介绍

在文章一开始我们强调, 不要再Mutation中进行异步操作.

  • 但是某些情况, 我们确实希望在Vuex中进行一些异步操作, 比如网络请求, 必然是异步的. 这个时候怎么处理呢?
  • Action类似于Mutation, 但是是用来代替Mutation进行异步操作的.

Action的基本使用代码如下:

  • context是什么?
    • context是和store对象具有相同方法和属性的对象.
    • 也就是说, 我们可以通过context去进行commit相关的操作, 也可以获取context.state等.
    • 但是注意, 这里它们并不是同一个对象, 为什么呢? 我们后面学习Modules的时候, 再具体说.

这样的代码是否多此一举呢?

  • 我们定义了actions, 然后又在actions中去进行commit, 这不是脱裤放屁吗?
  • 事实上并不是这样, 如果在Vuex中有异步操作, 那么我们就可以在actions中完成了.

5.2.Action异步操作

  • index.js中在Action中添加异步操作
    改变state中的数据,Action也不能跳过Mutation直接修改state中的数据,需要调用Mutation中的方法去改变state中属性的值。
  • App组件调用Action中的方法
  • 预览异步调用效果

5.3.Action异步操作结合Promise

  • 前面我们学习ES6语法的时候说过, Promise经常用于异步操作.

    • 在Action中, 我们可以将异步操作放在一个Promise中, 并且在成功或者失败后, 调用对应的resolve或reject.
  • OK, 我们来看下面的代码:

  • index.js文件中创建Promise对象

  • App组件打印异步请求返回日志

  • 预览异步请求结合Promise效果

5.4.案例代码总结

总结Action用到的完整代码

  • index.js文件完整代码
import Vue from 'vue'
import Vuex from 'vuex'
import * as types from './mutation-types'// 1.安装插件
Vue.use(Vuex)// 2.创建Vuex对象,实际上我们创建的是Vuex模块中Store类的对象
const store = new Vuex.Store({// 保存状态state: {counter: 100,students: [{ id: 110, name: 'why', age: 18 },{ id: 111, name: 'kobe', age: 24 },{ id: 112, name: 'james', age: 30 },{ id: 113, name: 'curry', age: 10 }],info: {name: 'kobe',age: 40,height: 1.98}},mutations: {// 通过定义方法改变state对象中属性的值increment(state) {unter++},decrement(state) {unter--},incrementCount(state, payload) {unter += unt},addStudent(state, stu) {state.students.push(stu)},[types.UPDATE_INFO](state, payload) {// 修改已初始化的属性,是响应式//state.info.name = '科比'// 这样添加新的没有初始化的属性,结果不是响应式// state.info['address'] = payload.address// 第一种响应式方式Vue.set(对象, '新的属性名称', 属性值)添加新的属性// Vue.set(state.info, 'address', payload.address)// 第二种响应式方式用新对象给旧对象重新赋值state.info = {...state.info, 'address':payload.address}}},actions: {// 默认参数context,相当于store对象作用 payload:当组件调用aincrementCount方法时,将参数封装成对象传递。aincrementCount(context, payload) {//1.Action的异步操作// setTimeout(() => {//   contextmit('incrementCount', payload)// },1000)// 2.Action异步操作结合Promisereturn new Promise((resolve,reject) => {setTimeout(() => {contextmit('incrementCount', payload)resolve()},1000)})}},getters: {// 定义一个属性more20stu获取函数返回值,这个原理和组件的comput一样more20stu(state) {// 获取年龄大于20岁的学生return state.students.filter(s => s.age > 20)},// 将getters对象作为参数传递到函数中more20stuLength(state, getters) {// 通过getters对象获取more20stu计算的结果,在这个结果上再次计算出数量。20stu.length},// getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数moreAgeStu(state) {// return function (age) {//   return state.students.filter(s => s.age > age)// }// 上面函数进行写法上优化使用箭头函数方式return age => {return state.students.filter(s => s.age > age)}}},modules: {}
})// 3.导出store对象
export default store 
  • App组件完整代码
<template><div id="app"><h2>{{ message }}</h2><!-- 使用Vuex插件store对象的state属性中的counter变量 --><h2>{{ $unter }}</h2><button @click="addtion">+</button><button @click="subtration">-</button><button @click="addCount(5)">+5</button><button @click="addStudent">添加学生</button><h2>----------App内容: info对象的内容是否是响应式----------</h2><h2>{{$store.state.info}}</h2><button @click="updateInfo('vue')">修改信息</button><h2>----------App内容: getters相关信息----------</h2><h2>{{$20stu}}</h2><!-- getters作为参数传递 --><h2>{{$20stuLength}}</h2><!-- getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数 --><h2>{{$AgeStu(12)}}</h2><!-- 使用HelloVuex组件模板 --><HelloVuex /></div>
</template><script>
import HelloVuex from "./components/HelloVuex";
import {UPDATE_INFO} from "./store/mutation-types"export default {name: "App",components: {HelloVuex,},data() {return {message: "我是App组件",};},methods: {addtion() {// 调用commit方法传入的参数就是我们index.js中mutations中定义的方法名称this.$storemit('increment');},subtration() {this.$storemit('decrement');},addCount(count) {// 普通的提交方式// this.$storemit('incrementCount',count);//payload提交参数风格,将传递的多个参数封装成对象传递// this.$storemit({//   type: 'incrementCount',//   count// })// dispatch调用Action中的aincrementCount方法// this.$store.dispatch('aincrementCount',{count})// Action结合Promisethis.$store.dispatch('aincrementCount', {count}).then(res => {console.log('完成了更新操作');})},addStudent() {const stu = {id:1, name: 'lina', age: 20}this.$storemit('addStudent', stu)},updateInfo(address) {this.$storemit({type: UPDATE_INFO,address})}},
};
</script><style>
</style>

6.Module

6.1.什么是Module

Module是模块的意思, 为什么在Vuex中我们要使用模块呢?

  • Vue使用单一状态树,那么也意味着很多状态都会交给Vuex来管理.
  • 当应用变得非常复杂时,store对象就有可能变得相当臃肿.
  • 为了解决这个问题, Vuex允许我们将store分割成模块(Module), 而每个模块拥有自己的state、mutations、actions、getters等

6.2.Module创建模块并调用模块内容案例

  • 1.在index.js中创建模块,并且为模块创建自己的state、mutations、actions、getters等
  • 2.App组件调用moduleA模块state的name值
  • 3.预览moduleA模块被App组件调用效果
  • 4.创建模块并调用模块内容案例代码
    index.js创建模块完整代码
import Vue from 'vue'
import Vuex from 'vuex'
import * as types from './mutation-types'// 1.安装插件
Vue.use(Vuex)// 创建对象
const moduleA = {state: {name: '宇宙'},mutations: {},actions: {},getters: {}
}
// 2.创建Vuex对象,实际上我们创建的是Vuex模块中Store类的对象
const store = new Vuex.Store({// 保存状态state: {counter: 100,students: [{ id: 110, name: 'why', age: 18 },{ id: 111, name: 'kobe', age: 24 },{ id: 112, name: 'james', age: 30 },{ id: 113, name: 'curry', age: 10 }],info: {name: 'kobe',age: 40,height: 1.98}},mutations: {// 通过定义方法改变state对象中属性的值increment(state) {unter++},decrement(state) {unter--},incrementCount(state, payload) {unter += unt},addStudent(state, stu) {state.students.push(stu)},[types.UPDATE_INFO](state, payload) {// 修改已初始化的属性,是响应式//state.info.name = '科比'// 这样添加新的没有初始化的属性,结果不是响应式// state.info['address'] = payload.address// 第一种响应式方式Vue.set(对象, '新的属性名称', 属性值)添加新的属性// Vue.set(state.info, 'address', payload.address)// 第二种响应式方式用新对象给旧对象重新赋值state.info = {...state.info, 'address':payload.address}}},actions: {// 默认参数context,相当于store对象作用 payload:当组件调用aincrementCount方法时,将参数封装成对象传递。aincrementCount(context, payload) {//1.Action的异步操作// setTimeout(() => {//   contextmit('incrementCount', payload)// },1000)// 2.Action异步操作结合Promisereturn new Promise((resolve,reject) => {setTimeout(() => {contextmit('incrementCount', payload)resolve()},1000)})}},getters: {// 定义一个属性more20stu获取函数返回值,这个原理和组件的comput一样more20stu(state) {// 获取年龄大于20岁的学生return state.students.filter(s => s.age > 20)},// 将getters对象作为参数传递到函数中more20stuLength(state, getters) {// 通过getters对象获取more20stu计算的结果,在这个结果上再次计算出数量。20stu.length},// getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数moreAgeStu(state) {// return function (age) {//   return state.students.filter(s => s.age > age)// }// 上面函数进行写法上优化使用箭头函数方式return age => {return state.students.filter(s => s.age > age)}}},modules: {// 在modules中引用创建的moduleA对象,此对象就是module模块a: moduleA}
})// 3.导出store对象
export default store 

App组件调用模块完整代码

<template><div id="app"><h2>----------App内容: modules中的内容----------</h2><!-- 通过store没有调用modules中的a,而是直接调用state中的a,原因是在modules中定义的模块会自动被state对象读取。所以相当于是在state中创建的a模块 --><h2>{{$store.state.a.name}}</h2><h2>{{ message }}</h2><!-- 使用Vuex插件store对象的state属性中的counter变量 --><h2>{{ $unter }}</h2><button @click="addtion">+</button><button @click="subtration">-</button><button @click="addCount(5)">+5</button><button @click="addStudent">添加学生</button><h2>----------App内容: info对象的内容是否是响应式----------</h2><h2>{{$store.state.info}}</h2><button @click="updateInfo('vue')">修改信息</button><h2>----------App内容: getters相关信息----------</h2><h2>{{$20stu}}</h2><!-- getters作为参数传递 --><h2>{{$20stuLength}}</h2><!-- getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数 --><h2>{{$AgeStu(12)}}</h2><!-- 使用HelloVuex组件模板 --><HelloVuex /></div>
</template><script>
import HelloVuex from "./components/HelloVuex";
import {UPDATE_INFO} from "./store/mutation-types"export default {name: "App",components: {HelloVuex,},data() {return {message: "我是App组件",};},methods: {addtion() {// 调用commit方法传入的参数就是我们index.js中mutations中定义的方法名称this.$storemit('increment');},subtration() {this.$storemit('decrement');},addCount(count) {// 普通的提交方式// this.$storemit('incrementCount',count);//payload提交参数风格,将传递的多个参数封装成对象传递// this.$storemit({//   type: 'incrementCount',//   count// })// dispatch调用Action中的aincrementCount方法// this.$store.dispatch('aincrementCount',{count})// Action结合Promisethis.$store.dispatch('aincrementCount', {count}).then(res => {console.log('完成了更新操作');})},addStudent() {const stu = {id:1, name: 'lina', age: 20}this.$storemit('addStudent', stu)},updateInfo(address) {this.$storemit({type: UPDATE_INFO,address})}},
};
</script><style>
</style>

6.3.Mutation修改模块属性值案例

  • 当我们需要修改state中属性的值,通过调用Mutations中的方法修改属性值。那么现在我们创建了模块,修改模块中state的属性值方式也是一样的。
  • 组件调用mutations中的方法,vue会先在store中的mutations中寻找这个方法,如果没有找到就会到模块中的mutations中去寻找。
  • 1.index.js模块moduleA中新增修改name属性方法
  • 2.App组件调用moduleA的mutations
  • 3.预览模块moduleA修改name属性值

修改模块属性值案例

  • 1.index.js中moduleA模块getter修改name属性值
  • 2.App组件调用moduleA模块getters的fullname方法修改name属性值
  • 3.预览getter修改属性值

获取根store中的属性案例

获取根store中state中的属性,可以传递一个rootState参数获取根store中state的属性。

  • 1.index.js获取根store的state的counter属性
  • 2.App组件调用getter的fullname2方法获取counter属性
  • 3.预览调用getter的fullname2方法获取counter属性

7.Actions

  • 当模块中有异步操作时,需要通过Actions操作Mutations修改state中属性值
  • Actions中context默认调用所在模块的Mutations中的方法。
  • 1.index.js actions调用mutations中updataName方法修改state的name属性值
  • 2.App组件调用Actions的aUpdataNamef方法
  • 3.预览Actions异步请求
s和Actions案例完整代码
  • inde.js文件完整代码
import Vue from 'vue'
import Vuex from 'vuex'
import * as types from './mutation-types'// 1.安装插件
Vue.use(Vuex)// 创建对象
const moduleA = {state: {name: '宇宙'},mutations: {// 在模块中添加修改name属性值的方法updateName(state, payload) {state.name = payload}},getters: {fullname(state, payload) {return state.name + '666'},// 通过rootState获取根store的state的counter属性值fullname2(state, getters, rootState) {return getters.fullname + unter}},actions: {// 调用的是本模块moduleA中的mutations中的方法aUpdateName(context) {setTimeout(() => {contextmit('updateName', '忍者神龟')},1000)}}
}
// 2.创建Vuex对象,实际上我们创建的是Vuex模块中Store类的对象
const store = new Vuex.Store({// 保存状态state: {counter: 100,students: [{ id: 110, name: 'why', age: 18 },{ id: 111, name: 'kobe', age: 24 },{ id: 112, name: 'james', age: 30 },{ id: 113, name: 'curry', age: 10 }],info: {name: 'kobe',age: 40,height: 1.98}},mutations: {// 通过定义方法改变state对象中属性的值increment(state) {unter++},decrement(state) {unter--},incrementCount(state, payload) {unter += unt},addStudent(state, stu) {state.students.push(stu)},[types.UPDATE_INFO](state, payload) {// 修改已初始化的属性,是响应式//state.info.name = '科比'// 这样添加新的没有初始化的属性,结果不是响应式// state.info['address'] = payload.address// 第一种响应式方式Vue.set(对象, '新的属性名称', 属性值)添加新的属性// Vue.set(state.info, 'address', payload.address)// 第二种响应式方式用新对象给旧对象重新赋值state.info = {...state.info, 'address':payload.address}}},actions: {// 默认参数context,相当于store对象作用 payload:当组件调用aincrementCount方法时,将参数封装成对象传递。aincrementCount(context, payload) {//1.Action的异步操作// setTimeout(() => {//   contextmit('incrementCount', payload)// },1000)// 2.Action异步操作结合Promisereturn new Promise((resolve,reject) => {setTimeout(() => {contextmit('incrementCount', payload)resolve()},1000)})}},getters: {// 定义一个属性more20stu获取函数返回值,这个原理和组件的comput一样more20stu(state) {// 获取年龄大于20岁的学生return state.students.filter(s => s.age > 20)},// 将getters对象作为参数传递到函数中more20stuLength(state, getters) {// 通过getters对象获取more20stu计算的结果,在这个结果上再次计算出数量。20stu.length},// getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数moreAgeStu(state) {// return function (age) {//   return state.students.filter(s => s.age > age)// }// 上面函数进行写法上优化使用箭头函数方式return age => {return state.students.filter(s => s.age > age)}}},modules: {// 在modules中引用创建的moduleA对象,此对象就是module模块a: moduleA}
})// 3.导出store对象
export default store 
  • App组件完整代码
<template><div id="app"><h2>----------App内容: modules中的内容----------</h2><!-- 通过store没有调用modules中的a,而是直接调用state中的a,原因是在modules中定义的模块会自动被state对象读取。所以相当于是在state中创建的a模块 --><h2>{{$store.state.a.name}}</h2><button @click="updateName">修改名字</button><!-- 调用moduleA模块getters的fullname方法修改name属性值 --><h2>{{$s.fullname}}</h2><!-- 通过rootState获取根store的state的counter属性值 --><h2>{{$s.fullname2}}</h2><!-- 调用module中的Actions方法异步请求 --><button @click="asyncUpdateName">异步修改名字</button><h2>----------App内容: store中的内容----------</h2><h2>{{ message }}</h2><!-- 使用Vuex插件store对象的state属性中的counter变量 --><h2>{{ $unter }}</h2><button @click="addtion">+</button><button @click="subtration">-</button><button @click="addCount(5)">+5</button><button @click="addStudent">添加学生</button><h2>----------App内容: info对象的内容是否是响应式----------</h2><h2>{{$store.state.info}}</h2><button @click="updateInfo('vue')">修改信息</button><h2>----------App内容: getters相关信息----------</h2><h2>{{$20stu}}</h2><!-- getters作为参数传递 --><h2>{{$20stuLength}}</h2><!-- getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数 --><h2>{{$AgeStu(12)}}</h2><!-- 使用HelloVuex组件模板 --><HelloVuex /></div>
</template><script>
import HelloVuex from "./components/HelloVuex";
import {UPDATE_INFO} from "./store/mutation-types"export default {name: "App",components: {HelloVuex,},data() {return {message: "我是App组件",};},methods: {addtion() {// 调用commit方法传入的参数就是我们index.js中mutations中定义的方法名称this.$storemit('increment');},subtration() {this.$storemit('decrement');},addCount(count) {// 普通的提交方式// this.$storemit('incrementCount',count);//payload提交参数风格,将传递的多个参数封装成对象传递// this.$storemit({//   type: 'incrementCount',//   count// })// dispatch调用Action中的aincrementCount方法// this.$store.dispatch('aincrementCount',{count})// Action结合Promisethis.$store.dispatch('aincrementCount', {count}).then(res => {console.log('完成了更新操作');})},addStudent() {const stu = {id:1, name: 'lina', age: 20}this.$storemit('addStudent', stu)},updateInfo(address) {this.$storemit({type: UPDATE_INFO,address})},updateName() {this.$storemit('updateName','浩瀚星空')},asyncUpdateName() {this.$store.dispatch('aUpdateName')}},
};
</script><style>
</style>

8.项目结构

  • 当我们的Vuex帮助我们管理过多的内容时, 好的项目结构可以让我们的代码更加清晰.
  • 下面项目结构中store结构树就是Vuex的结构,下面将我们的Vuex代码根据下图结构化

8.1.Vuex结构化

  • 现在我们Vuex管理的所有属性都在index.js文件中,当项目变得庞大的时候,管理的内容会非常复杂,都写在一个文件中不易管理和维护。
  • Vuex结构化思想:
    • 将Vuex中State、Mutations、getters、Actions、modules分别抽离到单独的文件中。
    • 在index.js文件以模块的方式导入State、Mutations、getters、Actions、modules进行调用。
8.1.1.抽离state内容到单独的对象

8.1.2.mutations内容抽离到mutations.js文件中

在store文件夹下创建mutations.js文件,并将mutations中内容抽离到该文件中。

  • mutations.js中的内容
import * as types from './mutation-types'export default {// 通过定义方法改变state对象中属性的值increment(state) {unter++},decrement(state) {unter--},incrementCount(state, payload) {unter += unt},addStudent(state, stu) {state.students.push(stu)},[types.UPDATE_INFO](state, payload) {// 修改已初始化的属性,是响应式//state.info.name = '科比'// 这样添加新的没有初始化的属性,结果不是响应式// state.info['address'] = payload.address// 第一种响应式方式Vue.set(对象, '新的属性名称', 属性值)添加新的属性// Vue.set(state.info, 'address', payload.address)// 第二种响应式方式用新对象给旧对象重新赋值state.info = {...state.info, 'address':payload.address}}
}
8.1.3.actions内容抽离到actions.js文件中

在store文件夹下创建actions.js文件,并将actions中内容抽离到该文件中。

  • actions.js文件中内容
export default  {// 默认参数context,相当于store对象作用 payload:当组件调用aincrementCount方法时,将参数封装成对象传递。aincrementCount(context, payload) {//1.Action的异步操作// setTimeout(() => {//   contextmit('incrementCount', payload)// },1000)// 2.Action异步操作结合Promisereturn new Promise((resolve,reject) => {setTimeout(() => {contextmit('incrementCount', payload)resolve()},1000)})}
}
8.s内容抽离到getters.js文件中

在store文件夹下创建getters.js文件,并将getters中内容抽离到该文件中。

  • getters.js文件中的内容
export default {// 定义一个属性more20stu获取函数返回值,这个原理和组件的comput一样more20stu(state) {// 获取年龄大于20岁的学生return state.students.filter(s => s.age > 20)},// 将getters对象作为参数传递到函数中more20stuLength(state, getters) {// 通过getters对象获取more20stu计算的结果,在这个结果上再次计算出数量。20stu.length},// getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数moreAgeStu(state) {// return function (age) {//   return state.students.filter(s => s.age > age)// }// 上面函数进行写法上优化使用箭头函数方式return age => {return state.students.filter(s => s.age > age)}}
}
8.dules内容抽离到modules.js文件中

在store文件夹下创建modules文件夹管理模块,每个模块都单独存放一个JS文件,将moduleA模块中内容抽离到moduleA.js文件中。

  • moduleA.js文件中内容
export default {state: {name: '宇宙'},mutations: {// 在模块中添加修改name属性值的方法updateName(state, payload) {state.name = payload}},getters: {fullname(state, payload) {return state.name + '666'},// 通过rootState获取根store的state的counter属性值fullname2(state, getters, rootState) {return getters.fullname + unter}},actions: {// 调用的是本模块moduleA中的mutations中的方法aUpdateName(context) {setTimeout(() => {contextmit('updateName', '忍者神龟')}, 1000)}}
}
8.1.6.index.js文件中导入所有模块

8.2. Vuex结构化后完整代码

8.2.1.store格式化后项目整体结构

8.2.2.index.js格式化后完整代码
import Vue from 'vue'
import Vuex from 'vuex'// 导入mutations、actions、getters、modules模块
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import moduleA from './modules/moduleA'// 1.安装插件
Vue.use(Vuex)const state = {counter: 100,students: [{ id: 110, name: 'why', age: 18 },{ id: 111, name: 'kobe', age: 24 },{ id: 112, name: 'james', age: 30 },{ id: 113, name: 'curry', age: 10 }],info: {name: 'kobe',age: 40,height: 1.98}
}
// 2.创建Vuex对象,实际上我们创建的是Vuex模块中Store类的对象
const store = new Vuex.Store({// 保存状态state,mutations,actions,getters,modules: {// 在modules中引用创建的moduleA对象,此对象就是module模块a: moduleA}
})// 3.导出store对象
export default store 
8.2.3.mutation-types.js格式化后完整代码
// 定义常量,并导出常量
export const UPDATE_INFO = 'UPDATE_INFO'
8.2.4.mutations.js格式化后完整代码
import * as types from './mutation-types'export default {// 通过定义方法改变state对象中属性的值increment(state) {unter++},decrement(state) {unter--},incrementCount(state, payload) {unter += unt},addStudent(state, stu) {state.students.push(stu)},[types.UPDATE_INFO](state, payload) {// 修改已初始化的属性,是响应式//state.info.name = '科比'// 这样添加新的没有初始化的属性,结果不是响应式// state.info['address'] = payload.address// 第一种响应式方式Vue.set(对象, '新的属性名称', 属性值)添加新的属性// Vue.set(state.info, 'address', payload.address)// 第二种响应式方式用新对象给旧对象重新赋值state.info = {...state.info, 'address':payload.address}}
}
8.2.5.actions.js格式化后完整代码
export default  {// 默认参数context,相当于store对象作用 payload:当组件调用aincrementCount方法时,将参数封装成对象传递。aincrementCount(context, payload) {//1.Action的异步操作// setTimeout(() => {//   contextmit('incrementCount', payload)// },1000)// 2.Action异步操作结合Promisereturn new Promise((resolve,reject) => {setTimeout(() => {contextmit('incrementCount', payload)resolve()},1000)})}
}
8.s.js格式化后完整代码
export default {// 定义一个属性more20stu获取函数返回值,这个原理和组件的comput一样more20stu(state) {// 获取年龄大于20岁的学生return state.students.filter(s => s.age > 20)},// 将getters对象作为参数传递到函数中more20stuLength(state, getters) {// 通过getters对象获取more20stu计算的结果,在这个结果上再次计算出数量。20stu.length},// getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数moreAgeStu(state) {// return function (age) {//   return state.students.filter(s => s.age > age)// }// 上面函数进行写法上优化使用箭头函数方式return age => {return state.students.filter(s => s.age > age)}}
}
8.duleA.js格式化后完整代码
export default {state: {name: '宇宙'},mutations: {// 在模块中添加修改name属性值的方法updateName(state, payload) {state.name = payload}},getters: {fullname(state, payload) {return state.name + '666'},// 通过rootState获取根store的state的counter属性值fullname2(state, getters, rootState) {return getters.fullname + unter}},actions: {// 调用的是本模块moduleA中的mutations中的方法aUpdateName(context) {setTimeout(() => {contextmit('updateName', '忍者神龟')}, 1000)}}
}

8.3.预览格式化后效果

本文发布于:2024-01-27 17:35:43,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17063481441680.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23