Vuex状态管理分层设计提高可维护性
- 模块划分:
- 根据业务功能将Vuex的状态管理划分为不同的模块。例如,在一个电商项目中,可以将用户相关的状态(如登录状态、用户信息等)放在
user
模块,商品相关的状态(如商品列表、购物车等)放在product
模块。这样每个模块负责自己业务范围内的状态管理,降低模块间的耦合度。
- 示例代码:
// store/user.ts
import { Module } from 'vuex';
import { RootState } from './index';
interface UserState {
isLoggedIn: boolean;
userInfo: { name: string; age: number } | null;
}
const userModule: Module<UserState, RootState> = {
state: {
isLoggedIn: false,
userInfo: null
},
mutations: {
SET_LOGGED_IN(state, value: boolean) {
state.isLoggedIn = value;
},
SET_USER_INFO(state, info: { name: string; age: number }) {
state.userInfo = info;
}
},
actions: {
login({ commit }, userData: { name: string; age: number }) {
// 模拟登录逻辑
commit('SET_LOGGED_IN', true);
commit('SET_USER_INFO', userData);
}
}
};
export default userModule;
- 命名空间:
- 使用命名空间(
namespaced: true
)为每个模块设置独立的命名空间。这可以避免不同模块中同名的mutation、action或getter之间的冲突。比如user
模块中的login
action不会与product
模块中的同名action混淆。
- 示例:
// store/user.ts
import { Module } from 'vuex';
import { RootState } from './index';
interface UserState {
isLoggedIn: boolean;
userInfo: { name: string; age: number } | null;
}
const userModule: Module<UserState, RootState> = {
namespaced: true,
state: {
isLoggedIn: false,
userInfo: null
},
mutations: {
SET_LOGGED_IN(state, value: boolean) {
state.isLoggedIn = value;
},
SET_USER_INFO(state, info: { name: string; age: number }) {
state.userInfo = info;
}
},
actions: {
login({ commit }, userData: { name: string; age: number }) {
// 模拟登录逻辑
commit('SET_LOGGED_IN', true);
commit('SET_USER_INFO', userData);
}
}
};
export default userModule;
- 状态抽象:
- 对一些通用的状态或操作进行抽象。例如,在多个模块中可能都需要处理加载状态,可以抽象出一个
loading
状态管理,通过一个LoadingModule
来统一管理各个模块的加载状态。这样在组件中使用时,可以方便地全局控制加载动画等。
- 示例:
// store/loading.ts
import { Module } from 'vuex';
import { RootState } from './index';
interface LoadingState {
module1Loading: boolean;
module2Loading: boolean;
}
const loadingModule: Module<LoadingState, RootState> = {
state: {
module1Loading: false,
module2Loading: false
},
mutations: {
SET_MODULE1_LOADING(state, value: boolean) {
state.module1Loading = value;
},
SET_MODULE2_LOADING(state, value: boolean) {
state.module2Loading = value;
}
},
actions: {
startModule1Loading({ commit }) {
commit('SET_MODULE1_LOADING', true);
},
stopModule1Loading({ commit }) {
commit('SET_MODULE1_LOADING', false);
}
}
};
export default loadingModule;
优化Vue Router的路由懒加载策略提升页面加载速度
- 动态导入语法:
- 使用ES2020的动态导入语法(
import()
)进行路由组件的懒加载。Vue Router支持这种语法来实现按需加载组件。例如:
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/home',
name: 'Home',
component: () => import('@/views/Home.vue')
},
{
path: '/about',
name: 'About',
component: () => import('@/views/About.vue')
}
]
});
export default router;
- 路由分组懒加载:
- 可以对路由进行分组懒加载,将相关的路由组件放在同一个代码块中。通过
const loadView = () => import(/* webpackChunkName: "group - views" */ '@/views/[name].vue');
这种方式,webpackChunkName
指定了打包后的代码块名称,这样相关的路由组件会被打包到同一个文件中,减少请求数量。例如:
import { createRouter, createWebHistory } from 'vue-router';
const loadView = () => import(/* webpackChunkName: "group - views" */ '@/views/[name].vue');
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/home',
name: 'Home',
component: loadView('Home')
},
{
path: '/about',
name: 'About',
component: loadView('About')
}
]
});
export default router;
- 预加载策略:
- 在合适的时机预加载一些可能会用到的路由组件。例如,在用户浏览当前页面时,可以提前预加载下一个可能访问的页面组件。可以使用
router.isReady()
方法结合router.beforeEach
钩子函数来实现。比如:
router.beforeEach(async (to, from, next) => {
const nextRoute = router.getRoutes().find(r => r.path === to.path);
if (nextRoute &&!nextRoute.components.default.__esModule) {
await nextRoute.components.default();
}
next();
});
利用TypeScript高级类型特性增强代码健壮性和可扩展性
- 类型别名和接口:
- 使用类型别名和接口来定义数据结构。在Vuex模块中,用接口定义状态、mutation的payload和action的参数类型。例如:
// store/user.ts
import { Module } from 'vuex';
import { RootState } from './index';
interface UserState {
isLoggedIn: boolean;
userInfo: { name: string; age: number } | null;
}
type LoginPayload = { name: string; age: number };
const userModule: Module<UserState, RootState> = {
state: {
isLoggedIn: false,
userInfo: null
},
mutations: {
SET_LOGGED_IN(state, value: boolean) {
state.isLoggedIn = value;
},
SET_USER_INFO(state, info: { name: string; age: number }) {
state.userInfo = info;
}
},
actions: {
login({ commit }, userData: LoginPayload) {
// 模拟登录逻辑
commit('SET_LOGGED_IN', true);
commit('SET_USER_INFO', userData);
}
}
};
export default userModule;
- 条件类型:
- 利用条件类型来实现更灵活的类型判断。比如在Vue Router的导航守卫中,可以根据不同的路由参数类型执行不同的逻辑。例如:
type AdminRoute = { path: '/admin', params: { role: 'admin' } };
type UserRoute = { path: '/user', params: { role: 'user' } };
type AnyRoute = AdminRoute | UserRoute;
function checkAccess(route: AnyRoute) {
type RouteRole = route extends AdminRoute? 'admin' : 'user';
if (route.params.role === RouteRole) {
// 执行相应权限的逻辑
}
}
- 映射类型:
- 在Vuex模块中,可以使用映射类型来批量转换对象的类型。例如,将一个对象的所有属性变为只读:
interface User {
name: string;
age: number;
}
type ReadonlyUser = {
readonly [P in keyof User]: User[P];
};
const user: User = { name: 'John', age: 30 };
const readonlyUser: ReadonlyUser = user as ReadonlyUser;
// readonlyUser.name = 'Jane'; // 报错,属性为只读