程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Vuex

    • Vuex 基本使用
    • 四个 Map 方法的使用
    • 模块化和命名空间
      • 1. 模块化的好处
      • 2. 修改 store.js
      • 3. 访问模块化 state
      • 4. 访问模块化 getters
      • 5. 调用模块化 actions
      • 6. 调用模块化 mutations
      • 7. 模块化文件结构
        • 1. 模块化文件的优势
        • 2. 创建模块化文件结构
        • 子模块1countAbout.js
        • 子模块2personAbout.js
        • 3. 注册子模块到 store/index.js
        • 手动注册模块
        • 使用 Webpack 自动注册模块
        • 使用 Vite 自动注册模块
    • Vue3 中使用 vuex
  • Vuex
  • Vuex
scholar
2024-08-03
目录

模块化和命名空间

# 模块化和命名空间

在大型应用中,Vuex 的 store 可能会变得非常庞大且难以维护。为了让代码更易于管理和维护,Vuex 提供了模块化和命名空间的机制。

# 1. 模块化的好处

  • 提高可维护性:将 store 分成多个独立的模块,各自管理自己的 state、mutations、actions 和 getters。这样可以使每个模块专注于特定的业务逻辑,降低复杂度。
  • 增强代码可读性:模块化的结构使得代码层次分明,易于理解。每个模块的职责清晰明确,便于新开发者快速上手。
  • 避免命名冲突:通过命名空间,确保模块内的命名不冲突。这种方式不仅提高了模块的独立性,也保证了代码的可维护性和扩展性。
  • 便于团队协作:不同开发人员可以专注于不同的模块,减少相互之间的干扰,提高开发效率

使用命名空间的主要目的

通过为每个模块定义独立的命名空间,可以避免不同模块之间的状态、变更方法、操作方法和计算属性的命名冲突。例如,两个模块中都有 count 状态,通过命名空间,可以区分为 moduleA/count 和 moduleB/count。

# 2. 修改 store.js

在 store.js 中,将 store 拆分为多个模块,每个模块都有自己的 state、mutations、actions 和 getters,并通过 namespaced: true 开启命名空间。

import Vue from 'vue'; // 引入 Vue 框架
import Vuex from 'vuex'; // 引入 Vuex 库

Vue.use(Vuex); // 将 Vuex 安装为 Vue 插件

// countAbout 模块
const countAbout = {
  namespaced: true, // 开启命名空间
  state: { x: 1 }, // 模块的 state
  mutations: {
    // 模块的 mutations
    JIA(state, value) {
      state.x += value; // 修改 state 中的 x
    }
  },
  actions: {
    // 模块的 actions
    jia(context, value) {
      context.commit('JIA', value); // 提交 JIA mutation
    }
  },
  getters: {
    // 模块的 getters
    bigSum(state) {
      return state.x * 10; // 计算 x 的十倍
    }
  }
};

// personAbout 模块
const personAbout = {
  namespaced: true, // 开启命名空间
  state: { list: [] }, // 模块的 state
  mutations: {
    // 添加一个人到列表中
    ADD_PERSON(state, person) {
      state.list.push(person); // 向 list 中添加一个 person
    }
  },
  actions: {
    // 添加名为 Wang 的人
    addPersonWang(context, person) {
      if (person.name === 'Wang') {
        context.commit('ADD_PERSON', person); // 提交 ADD_PERSON mutation
      }
    }
  }
};

// 创建并导出 Vuex Store 实例
const store = new Vuex.Store({
  modules: {
    countAbout, // 注册 countAbout 模块
    personAbout // 注册 personAbout 模块
  }
});

export default store; // 导出 store 实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 3. 访问模块化 state

笔记

模块化以后,你只需要在原来的 mapState、mapGetters、mapActions 和 mapMutations 的语法之前加上对应的模块名称就可以了。这样可以确保你访问和操作的是指定模块中的状态、计算属性、动作和变更。

在组件中,访问模块化的 state 有两种方式:

  1. 直接访问 state:

    // 直接通过路径访问模块的 state
    this.$store.state.personAbout.list; // 访问 personAbout 模块的 list
    
    1
    2
  2. 使用 mapState 辅助函数:

    import { mapState } from 'vuex';
    
    computed: {
      ...mapState('countAbout', ['x']) // 将 countAbout 模块的 x 映射为计算属性
    }
    
    1
    2
    3
    4
    5

# 4. 访问模块化 getters

  1. 直接访问 getters:

    // 通过路径和名称访问模块的 getters
    this.$store.getters['countAbout/bigSum']; // 访问 countAbout 模块的 bigSum getter
    
    1
    2
  2. 使用 mapGetters 辅助函数:

    import { mapGetters } from 'vuex';
    
    computed: {
      ...mapGetters('countAbout', ['bigSum']) // 将 countAbout 模块的 bigSum 映射为计算属性
    }
    
    1
    2
    3
    4
    5

# 5. 调用模块化 actions

  1. 直接调用 dispatch:

    // 使用路径和名称直接调度模块的 actions
    this.$store.dispatch('personAbout/addPersonWang', person); // 调用 personAbout 模块的 addPersonWang action
    
    1
    2
  2. 使用 mapActions 辅助函数:

    import { mapActions } from 'vuex';
    
    methods: {
      ...mapActions('countAbout', {
        incrementOdd: 'jiaOdd', // 将 countAbout 模块的 jiaOdd action 映射为 incrementOdd 方法
        incrementWait: 'jiaWait' // 将 countAbout 模块的 jiaWait action 映射为 incrementWait 方法
      })
    }
    
    1
    2
    3
    4
    5
    6
    7
    8

# 6. 调用模块化 mutations

  1. 直接调用 commit:

    // 使用路径和名称直接提交模块的 mutations
    this.$store.commit('personAbout/ADD_PERSON', person); // 调用 personAbout 模块的 ADD_PERSON mutation
    
    1
    2
  2. 使用 mapMutations 辅助函数:

    import { mapMutations } from 'vuex';
    
    methods: {
      ...mapMutations('countAbout', {
        increment: 'JIA', // 将 countAbout 模块的 JIA mutation 映射为 increment 方法
        decrement: 'JIAN' // 将 countAbout 模块的 JIAN mutation 映射为 decrement 方法
      })
    }
    
    1
    2
    3
    4
    5
    6
    7
    8

# 7. 模块化文件结构

在大型 Vue.js 应用中,随着业务逻辑的增加,单一的 store 文件可能会变得复杂且难以管理。通过模块化可以将 store 分解为多个独立的模块,每个模块管理自己独立的 state、mutations、actions 和 getters。这种方式不仅提高了代码的可读性和可维护性,还使得开发过程更为清晰易懂。

# 1. 模块化文件的优势

  • 结构更清晰:模块化文件使得代码结构更加清晰,每个文件只关注特定的功能和业务逻辑,从而使得整个项目的组织更为合理。
  • 易于维护:由于每个模块相对独立,在某个模块中进行变更或修复不会影响到其他模块,降低了整体维护成本。
  • 提高复用性:通过模块化可以更方便地在项目中复用代码,不同模块可以独立开发、测试和维护。
  • 协作开发:在团队开发中,模块化允许多个开发者同时在不同模块中工作,而不会互相干扰,提高了开发效率。

# 2. 创建模块化文件结构

将 store 的每个模块分拆为单独的文件存储在 modules 目录中。在 store/index.js 中引入这些模块,以便集成到 Vuex store 中。

文件目录结构

src/
  └── store/
      ├── index.js          // 主 store 配置文件
      ├── modules/          // 存储各个子模块
      │   ├── countAbout.js // countAbout 模块
      │   └── personAbout.js// personAbout 模块
1
2
3
4
5
6

# 子模块1countAbout.js

// store/modules/countAbout.js

// 定义模块的状态
const state = {
  x: 1 // 模块的初始状态值
};

// 定义模块的变更方法
const mutations = {
  // 增加 x 的值
  JIA(state, value) {
    state.x += value; // 修改 state.x 的值
  }
};

// 定义模块的操作方法
const actions = {
  // 触发 JIA mutation
  jia({ commit }, value) {
    commit('JIA', value); // 提交 JIA mutation 来修改 state
  }
};

// 定义模块的计算属性
const getters = {
  // 计算属性 bigSum,返回 x 的十倍
  bigSum(state) {
    return state.x * 10; // 返回 state.x 的十倍值
  }
};

// 导出模块
export default {
  namespaced: true, // 启用命名空间
  state,
  mutations,
  actions,
  getters
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 子模块2personAbout.js

// store/modules/personAbout.js

// 定义模块的状态
const state = {
  list: [] // 存储人员列表的状态
};

// 定义模块的变更方法
const mutations = {
  // 向列表中添加新人员
  ADD_PERSON(state, person) {
    state.list.push(person); // 将新人员添加到 list 数组中
  }
};

// 定义模块的操作方法
const actions = {
  // 添加名为 "Wang" 的人员
  addPersonWang({ commit }, person) {
    if (person.name === 'Wang') {
      commit('ADD_PERSON', person); // 如果名字是 Wang,提交 ADD_PERSON mutation
    }
  }
};

// 导出模块
export default {
  namespaced: true, // 启用命名空间
  state,
  mutations,
  actions
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 3. 注册子模块到 store/index.js

# 手动注册模块

对于模块数量较少或不使用自动化工具的项目,可以手动注册子模块到主 store 配置文件。

import Vue from 'vue'; // 引入 Vue 框架
import Vuex from 'vuex'; // 引入 Vuex 库
import countAbout from './modules/countAbout'; // 导入 countAbout 模块
import personAbout from './modules/personAbout'; // 导入 personAbout 模块

Vue.use(Vuex); // 将 Vuex 安装为 Vue 插件

// 创建并导出 Vuex store 实例
const store = new Vuex.Store({
  modules: {
    countAbout, // 注册 countAbout 模块到 Vuex Store
    personAbout // 注册 personAbout 模块到 Vuex Store
  }
});

export default store; // 导出 store 实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 使用 Webpack 自动注册模块

在 Vue 项目中,Webpack 提供了 require.context API,可以实现自动化模块注册。这对于使用 Webpack 构建的项目非常有用。

import Vue from 'vue'; // 引入 Vue 框架
import Vuex from 'vuex'; // 引入 Vuex 库

Vue.use(Vuex); // 将 Vuex 安装为 Vue 插件

// 使用 Webpack 的 require.context 方法自动加载 ./modules 目录下的所有以 .js 结尾的模块文件
const modulesFiles = require.context('./modules', true, /\.js$/);

// 遍历加载的模块文件,将每个模块的导出对象收集到一个名为 modules 的对象中
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // 获取模块名称 './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1');
  const value = modulesFiles(modulePath);
  modules[moduleName] = value.default;
  return modules;
}, {});

// 创建一个 Vuex store 实例,传入之前收集到的模块对象
const store = new Vuex.Store({
  modules // 注册所有模块
});

export default store; // 导出 store 实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  • require.context:Webpack 提供的 API,用于创建一个上下文模块,可以批量引入某个目录下的模块。

    • 第一个参数:要搜索的目录 (./modules)。
    • 第二个参数:一个布尔值,表示是否也查询其子目录 (true)。
    • 第三个参数:一个正则表达式,匹配文件名 (/\.js$/)。
  • modulesFiles.keys():返回匹配的模块路径数组。

  • reduce():遍历每个模块路径,加载模块并将其添加到 modules 对象中。

  • moduleName:去掉路径和文件扩展名后的模块名称。

  • value.default:每个模块的默认导出对象。

# 使用 Vite 自动注册模块

在 Vue 3 项目中,如果使用 Vite 作为构建工具,可以利用 Vite 提供的 import.meta.glob 来实现模块的自动化注册。

import { createStore } from 'vuex'; // Vuex 4 在 Vue 3 中使用

// 使用 import.meta.glob 来批量导入模块
const modulesFiles = import.meta.glob('./modules/*.js');

// 遍历加载的模块,并将其添加到 modules 对象中
const modules = {};
for (const path in modulesFiles) {
  modulesFiles[path]().then((module) => {
    const moduleName = path.replace(/^\.\/modules\/(.*)\.\w+$/, '$1');
    modules[moduleName] = module.default;
  });
}

// 创建并导出 Vuex store 实例
const store = createStore({
  modules // 注册所有模块
});

export default store; // 导出 store 实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  • import.meta.glob:Vite 提供的 API,用于批量导入匹配指定模式的模块。

    • 模式:指定要导入的文件('./modules/*.js' 表示导入 modules 目录下所有 .js 文件)。
  • modulesFiles[path]():返回一个 Promise,通过 then 方法异步加载模块。

  • module.default:获取模块的默认导出对象,并将其添加到 modules 对象中。

编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08
四个 Map 方法的使用
Vue3 中使用 vuex

← 四个 Map 方法的使用 Vue3 中使用 vuex→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式