From b397e00b3611f1f2c00a51c4b614119777a57d68 Mon Sep 17 00:00:00 2001
From: bunny <1319900154@qq.com>
Date: Thu, 19 Jun 2025 19:41:57 +0800
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Vuex=20=E7=8A=B6=E6=80=81=E6=98=A0?=
=?UTF-8?q?=E5=B0=84=E4=B8=8E=E6=A8=A1=E5=9D=97=E5=8C=96=E6=9C=80=E4=BD=B3?=
=?UTF-8?q?=E5=AE=9E=E8=B7=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
vue2-tutorials/single-file/demo2/src/App.vue | 8 +-
.../single-file/demo2/src/store/index.js | 4 +-
.../demo2/src/store/modules/schoolInfo.js | 16 ++
.../demo5/Vuex 状态映射与模块化最佳实践.md | 199 ++++++++++++++++++
.../demo2/src/views/demo5/index.vue | 30 +++
5 files changed, 253 insertions(+), 4 deletions(-)
create mode 100644 vue2-tutorials/single-file/demo2/src/store/modules/schoolInfo.js
create mode 100644 vue2-tutorials/single-file/demo2/src/views/demo5/Vuex 状态映射与模块化最佳实践.md
create mode 100644 vue2-tutorials/single-file/demo2/src/views/demo5/index.vue
diff --git a/vue2-tutorials/single-file/demo2/src/App.vue b/vue2-tutorials/single-file/demo2/src/App.vue
index 28fcb9e..a0aa594 100644
--- a/vue2-tutorials/single-file/demo2/src/App.vue
+++ b/vue2-tutorials/single-file/demo2/src/App.vue
@@ -5,7 +5,8 @@
-->
-
+
+
@@ -13,11 +14,12 @@
// import Demo1 from "@/views/demo1/index.vue";
// import Demo2 from "@/views/demo2/index.vue";
// import Demo3 from "@/views/demo3/index.vue";
-import Demo4 from "@/views/demo4/index.vue";
+// import Demo4 from "@/views/demo4/index.vue";
+import Demo5 from "@/views/demo5/index.vue";
export default {
name: "App",
// components: { Demo1, Demo2, Demo3 },
- components: { Demo4 },
+ components: { Demo5 },
};
diff --git a/vue2-tutorials/single-file/demo2/src/store/index.js b/vue2-tutorials/single-file/demo2/src/store/index.js
index 6fedd6b..80dc90d 100644
--- a/vue2-tutorials/single-file/demo2/src/store/index.js
+++ b/vue2-tutorials/single-file/demo2/src/store/index.js
@@ -1,13 +1,15 @@
import Vue from "vue";
import Vuex from "vuex";
import count from "./modules/count";
+import schoolInfo from "./modules/schoolInfo";
+
Vue.use(Vuex);
const store = new Vuex.Store({
state: {},
mutations: {},
actions: {},
- modules: { count },
+ modules: { count, schoolInfo },
});
export default store;
diff --git a/vue2-tutorials/single-file/demo2/src/store/modules/schoolInfo.js b/vue2-tutorials/single-file/demo2/src/store/modules/schoolInfo.js
new file mode 100644
index 0000000..bec4cdb
--- /dev/null
+++ b/vue2-tutorials/single-file/demo2/src/store/modules/schoolInfo.js
@@ -0,0 +1,16 @@
+const schoolInfo = {
+ namespaced: true,
+ state: {
+ schoolName: "BunnySchool",
+ schoolAddress: "昆山市印象欧洲",
+ },
+ getters: {
+ getSchoolName(state) {
+ return state.schoolName + "---";
+ },
+ },
+ actions: {},
+ mutations: {},
+};
+
+export default schoolInfo;
diff --git a/vue2-tutorials/single-file/demo2/src/views/demo5/Vuex 状态映射与模块化最佳实践.md b/vue2-tutorials/single-file/demo2/src/views/demo5/Vuex 状态映射与模块化最佳实践.md
new file mode 100644
index 0000000..d4672c2
--- /dev/null
+++ b/vue2-tutorials/single-file/demo2/src/views/demo5/Vuex 状态映射与模块化最佳实践.md
@@ -0,0 +1,199 @@
+# Vuex 状态映射与模块化最佳实践
+
+## 一、状态访问方式对比
+
+### 1. 直接访问方式
+```javascript
+// 原始访问方式(不推荐)
+this.$store.state.schoolInfo.schoolName
+this.$store.getters['schoolInfo/getSchoolName']
+```
+
+### 2. 映射辅助函数
+```javascript
+// 推荐使用mapState/mapGetters
+import { mapState, mapGetters } from 'vuex'
+
+computed: {
+ // 数组写法(同名映射)
+ ...mapState('schoolInfo', ['schoolName']),
+ ...mapGetters('schoolInfo', ['getSchoolName']),
+
+ // 对象写法(重命名)
+ ...mapState('schoolInfo', {
+ mySchoolName: 'schoolName'
+ }),
+ ...mapGetters('schoolInfo', {
+ formattedName: 'getSchoolName'
+ })
+}
+```
+
+## 二、模块化配置详解
+
+### 1. 模块定义规范
+```javascript
+const schoolInfo = {
+ namespaced: true, // 必须开启命名空间
+ state: () => ({ // 使用函数返回状态对象
+ schoolName: "BunnySchool",
+ schoolAddress: "昆山市印象欧洲"
+ }),
+ getters: {
+ getSchoolName(state) {
+ // 可组合其他getters
+ return `${state.schoolName}---${state.schoolAddress}`
+ }
+ },
+ mutations: {
+ // 使用常量类型
+ UPDATE_NAME(state, payload) {
+ state.schoolName = payload
+ }
+ },
+ actions: {
+ async fetchSchoolInfo({ commit }) {
+ const res = await api.getSchoolInfo()
+ commit('UPDATE_NAME', res.data.name)
+ }
+ }
+}
+```
+
+### 2. 模块注册方式
+```javascript
+// store/index.js
+import schoolInfo from './modules/schoolInfo'
+
+export default new Vuex.Store({
+ modules: {
+ schoolInfo // 键名将作为命名空间前缀
+ }
+})
+```
+
+## 三、最佳实践指南
+
+### 1. 命名规范建议
+| 类型 | 命名规则 | 示例 |
+| -------- | ----------- | ----------------- |
+| 模块文件 | kebab-case | `school-info.js` |
+| state | camelCase | `studentCount` |
+| mutation | 大写+下划线 | `UPDATE_INFO` |
+| getter | 动词短语 | `getFilteredList` |
+| action | 业务动作 | `fetchSchoolData` |
+
+### 2. 组件中使用建议
+```javascript
+export default {
+ computed: {
+ // 优先使用映射辅助函数
+ ...mapState('schoolInfo', ['schoolName']),
+
+ // 复杂计算使用本地计算属性
+ formattedAddress() {
+ return this.$store.state.schoolInfo.schoolAddress.replace('市', '')
+ }
+ },
+ methods: {
+ ...mapMutations('schoolInfo', ['UPDATE_NAME']),
+
+ // 组合多个action
+ async refreshData() {
+ await this.$store.dispatch('schoolInfo/fetchSchoolInfo')
+ this.loadComplete()
+ }
+ }
+}
+```
+
+### 3. 代码组织技巧
+```
+store/
+├── index.js # 主入口
+├── modules/
+│ ├── school-info.js # 学校模块
+│ └── user.js # 用户模块
+└── types.js # mutation类型常量
+```
+
+## 四、高级应用场景
+
+### 1. 动态模块注册
+```javascript
+// 按需加载模块
+export default {
+ created() {
+ import('./store/modules/school-info').then(module => {
+ this.$store.registerModule('schoolInfo', module.default)
+ })
+ },
+ destroyed() {
+ this.$store.unregisterModule('schoolInfo')
+ }
+}
+```
+
+### 2. 模块复用
+```javascript
+// 创建可复用模块工厂
+function createSchoolModule(initialName) {
+ return {
+ namespaced: true,
+ state: () => ({
+ schoolName: initialName
+ }),
+ // ...其他配置
+ }
+}
+```
+
+### 3. 插件开发
+```javascript
+// 状态持久化插件
+const persistPlugin = store => {
+ // 初始化时读取
+ const savedState = localStorage.getItem('vuex_state')
+ if (savedState) {
+ store.replaceState(JSON.parse(savedState))
+ }
+
+ // 订阅mutation变化
+ store.subscribe((mutation, state) => {
+ localStorage.setItem('vuex_state', JSON.stringify(state))
+ })
+}
+```
+
+## 五、常见问题解决方案
+
+1. **模块热更新**:
+ ```javascript
+ if (module.hot) {
+ module.hot.accept(['./modules/school-info'], () => {
+ store.hotUpdate({
+ modules: {
+ schoolInfo: require('./modules/school-info').default
+ }
+ })
+ })
+ }
+ ```
+
+2. **循环依赖处理**:
+ - 使用全局getter解决跨模块访问
+ - 通过rootState参数访问根状态
+
+3. **TypeScript支持**:
+ ```typescript
+ // 定义模块类型
+ interface SchoolState {
+ schoolName: string
+ schoolAddress: string
+ }
+
+ const schoolInfo: Module = {
+ namespaced: true,
+ state: () => ({ /* 初始状态 */ })
+ }
+ ```
diff --git a/vue2-tutorials/single-file/demo2/src/views/demo5/index.vue b/vue2-tutorials/single-file/demo2/src/views/demo5/index.vue
new file mode 100644
index 0000000..a84e5df
--- /dev/null
+++ b/vue2-tutorials/single-file/demo2/src/views/demo5/index.vue
@@ -0,0 +1,30 @@
+
+
+
{{ $store.state.schoolInfo.schoolName }}
+ {{ schoolName }}
+ {{ $store.getters["schoolInfo/getSchoolName"] }}
+ {{ getSchoolName }}
+
+
+
+