Compare commits
No commits in common. "39b773f4094a1b3925803a24cc759713021aec7c" and "b878032303b1a03a594de8658ea96d661a4ccd39" have entirely different histories.
39b773f409
...
b878032303
|
@ -10,7 +10,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"vue": "^2.6.14",
|
"vue": "^2.6.14",
|
||||||
"vue-router": "3",
|
|
||||||
"vuex": "3"
|
"vuex": "3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -14,9 +14,6 @@ importers:
|
||||||
vue:
|
vue:
|
||||||
specifier: ^2.6.14
|
specifier: ^2.6.14
|
||||||
version: 2.7.16
|
version: 2.7.16
|
||||||
vue-router:
|
|
||||||
specifier: '3'
|
|
||||||
version: 3.6.5(vue@2.7.16)
|
|
||||||
vuex:
|
vuex:
|
||||||
specifier: '3'
|
specifier: '3'
|
||||||
version: 3.6.2(vue@2.7.16)
|
version: 3.6.2(vue@2.7.16)
|
||||||
|
@ -3578,11 +3575,6 @@ packages:
|
||||||
vue:
|
vue:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
vue-router@3.6.5:
|
|
||||||
resolution: {integrity: sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ==}
|
|
||||||
peerDependencies:
|
|
||||||
vue: ^2
|
|
||||||
|
|
||||||
vue-style-loader@4.1.3:
|
vue-style-loader@4.1.3:
|
||||||
resolution: {integrity: sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==}
|
resolution: {integrity: sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==}
|
||||||
|
|
||||||
|
@ -7708,10 +7700,6 @@ snapshots:
|
||||||
'@vue/compiler-sfc': 3.5.16
|
'@vue/compiler-sfc': 3.5.16
|
||||||
vue: 2.7.16
|
vue: 2.7.16
|
||||||
|
|
||||||
vue-router@3.6.5(vue@2.7.16):
|
|
||||||
dependencies:
|
|
||||||
vue: 2.7.16
|
|
||||||
|
|
||||||
vue-style-loader@4.1.3:
|
vue-style-loader@4.1.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
hash-sum: 1.0.2
|
hash-sum: 1.0.2
|
||||||
|
|
|
@ -1,35 +1,15 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="">
|
<html lang="">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<link
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css"
|
|
||||||
rel="stylesheet"
|
|
||||||
integrity="sha384-LN+7fdVzj6u52u30Kp6M/trliBMCMKTyK833zpbD+pXdCLuTusPj697FH4R/5mcr"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/>
|
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
|
|
||||||
<script
|
|
||||||
src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
|
|
||||||
integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
></script>
|
|
||||||
<script
|
|
||||||
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.min.js"
|
|
||||||
integrity="sha384-7qAoOXltbVP82dhxHAUje59V5r2YsVfBafyUDxEdApLPmcdhBPg1DKg1ERo0BZlK"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
></script>
|
|
||||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
<strong
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
|
|
||||||
properly without JavaScript enabled. Please enable it to
|
|
||||||
continue.</strong
|
|
||||||
>
|
|
||||||
</noscript>
|
</noscript>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<!-- built files will be auto injected -->
|
<!-- built files will be auto injected -->
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
<Demo2 />
|
<Demo2 />
|
||||||
<hr />
|
<hr />
|
||||||
<Demo3 /> -->
|
<Demo3 /> -->
|
||||||
<!-- <Demo4 /> -->
|
<Demo4 />
|
||||||
<Demo6 />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -14,13 +13,11 @@
|
||||||
// import Demo1 from "@/views/demo1/index.vue";
|
// import Demo1 from "@/views/demo1/index.vue";
|
||||||
// import Demo2 from "@/views/demo2/index.vue";
|
// import Demo2 from "@/views/demo2/index.vue";
|
||||||
// import Demo3 from "@/views/demo3/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";
|
|
||||||
import Demo6 from "@/views/demo6/index.vue";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
// components: { Demo1, Demo2, Demo3 },
|
// components: { Demo1, Demo2, Demo3 },
|
||||||
components: { Demo6 },
|
components: { Demo4 },
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import VueRouter from "vue-router";
|
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import router from "./router";
|
|
||||||
import store from "./store";
|
import store from "./store";
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
Vue.use(VueRouter);
|
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
render: (h) => h(App),
|
render: (h) => h(App),
|
||||||
store,
|
store,
|
||||||
router,
|
|
||||||
}).$mount("#app");
|
}).$mount("#app");
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
import VueRouter from "vue-router";
|
|
||||||
|
|
||||||
const router = new VueRouter({
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
path: "/about",
|
|
||||||
component: () => import("@/views/demo6/components/About.vue"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/home",
|
|
||||||
component: () => import("@/views/demo6/components/Home.vue"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
export default router;
|
|
|
@ -1,15 +1,13 @@
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import Vuex from "vuex";
|
import Vuex from "vuex";
|
||||||
import count from "./modules/count";
|
import count from "./modules/count";
|
||||||
import schoolInfo from "./modules/schoolInfo";
|
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
state: {},
|
state: {},
|
||||||
mutations: {},
|
mutations: {},
|
||||||
actions: {},
|
actions: {},
|
||||||
modules: { count, schoolInfo },
|
modules: { count },
|
||||||
});
|
});
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
const schoolInfo = {
|
|
||||||
namespaced: true,
|
|
||||||
state: {
|
|
||||||
schoolName: "BunnySchool",
|
|
||||||
schoolAddress: "昆山市印象欧洲",
|
|
||||||
},
|
|
||||||
getters: {
|
|
||||||
getSchoolName(state) {
|
|
||||||
return state.schoolName + "---";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {},
|
|
||||||
mutations: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default schoolInfo;
|
|
|
@ -1,199 +0,0 @@
|
||||||
# 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<SchoolState, RootState> = {
|
|
||||||
namespaced: true,
|
|
||||||
state: () => ({ /* 初始状态 */ })
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,30 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<h3>{{ $store.state.schoolInfo.schoolName }}</h3>
|
|
||||||
<h3>{{ schoolName }}</h3>
|
|
||||||
<h3>{{ $store.getters["schoolInfo/getSchoolName"] }}</h3>
|
|
||||||
<h3>{{ getSchoolName }}</h3>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapState, mapGetters } from "vuex";
|
|
||||||
export default {
|
|
||||||
name: "Demo-5",
|
|
||||||
data() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
// mapState和mapGetters对象写法
|
|
||||||
// ...mapState("schoolInfo", { schoolName: "schoolName" }),
|
|
||||||
|
|
||||||
// mapState和mapGetters数组写法
|
|
||||||
...mapState("schoolInfo", ["schoolName"]),
|
|
||||||
...mapGetters("schoolInfo", ["getSchoolName"]),
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
const data = mapState("schoolInfo", { schoolName: "schoolName" });
|
|
||||||
console.log(data);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
|
@ -1,11 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<h2>About内容</h2>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "AboutPage",
|
|
||||||
};
|
|
||||||
</script>
|
|
|
@ -1,11 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<h3>Home内容</h3>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "HomePage",
|
|
||||||
};
|
|
||||||
</script>
|
|
|
@ -1,39 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="container mt-3">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-2 col-xs-offset-2 text-center">
|
|
||||||
<!-- 路由跳转内容 -->
|
|
||||||
<div class="list-group">
|
|
||||||
<router-link
|
|
||||||
class="list-group-item"
|
|
||||||
active-class="active"
|
|
||||||
to="/about"
|
|
||||||
>
|
|
||||||
about
|
|
||||||
</router-link>
|
|
||||||
<router-link class="list-group-item" active-class="active" to="/home"
|
|
||||||
>home</router-link
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 内容显示区域 -->
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<div class="panel">
|
|
||||||
<div class="panel-body">
|
|
||||||
<router-view />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "Demo-6",
|
|
||||||
data() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
Loading…
Reference in New Issue