✍️ 项目实践分享
- 如何让编写的代码更加优雅、简洁、可读性高、并且易于维护和扩展;在日常工作中要多总结与思考,特别是关于全局性的设计、架构、代码规范的思考。
- 以下是项目实践分享的示例代码
全局路由封装
文档描述
- 路由入口
src/router/index.js; - 路由守卫
src/router/guard.js - 报错修复
src/router/error-handling.js - 认证登录
src/router/auth.js - 配置合并
src/router/routes.js - 子路由
src/router/modules; - 通过 webpack 的
require.context引入, 后续新增路由,直接在子路由路径增加xxx.js即可
js
/**
* 路由主入口 index.js
*/
import Vue from 'vue';
import Router from 'vue-router';
import { routes } from './routes';
import { fixNavigationDuplication } from './error-handling';
import { setupBeforeEachGuard, setupAfterEachGuard } from './guards';
Vue.use(Router);
// 修复路由导航重复问题
fixNavigationDuplication();
// 创建路由实例
const router = new Router({
linkActiveClass: 'linkActive',
base: __dirname,
routes,
});
// 设置路由守卫
setupBeforeEachGuard(router);
setupAfterEachGuard(router);
export default router;示例代码
展开
- routes.jsjs
// 动态导入子路由模块 const requireModule = require.context('./modules', false, /\.js$/); const moduleRoutes = requireModule .keys() .map((file) => requireModule(file).default) .flat(); //...省略代码... export default routes; - guard.jsjs
/** * 路由前置守卫 * @param {Object} router - 路由实例 */ export const setupBeforeEachGuard = (router) => { router.beforeEach((to, from, next) => {// 路由守卫逻辑 // 路由变化时取消所有待处理的请求 cancelAllPendingRequests('路由已变化,请求已取消'); // 已登录时访问根路径或登录页,重定向到首页 if (loggedIn && (to.path === '/' || to.path === '/login')) { next({ path: '/welCome' }); return; } //...省略代码... // 已登录且路由存在,正常导航 if (loggedIn && to.matched.length) { next(); return; } // 路由不存在,导航到404页面 if (to.matched.length === 0) { next({ path: '/notfound' }); return; } // 默认情况,正常导航 next(); }); }; export default { setupBeforeEachGuard, setupAfterEachGuard, };
全局axios封装
文档描述
- HTTP处理入口
src/fetch/index.js; - 基本设置
src/fetch/config.js - 报错提示
src/fetch/error-handling.js - 超时提示
src/fetch/loading.js - 取消处理
src/fetch/cancel.js - axios拦截
src/fetch/interceptors.js - 请求&响应处理
src/fetch/request.js - 清理登录信息
src/fetch/clearAuth.js - api动态注册
src/fetch/api-registry.js - 各模块api
src/fetch/modules; - 通过 webpack 的
require.context引入, 后续新增api,直接在modules下xxx.js即可
js
/**
* HTTP 请求模块主入口
* from OPS @lixiaopeng used by @henson 2025年7月16日
*/
import { initAxiosConfig } from './config';
import { setupRequestInterceptor, setupResponseInterceptor } from './interceptors';
import { buildApiObject } from './api-registry';
// 初始化 axios 配置
initAxiosConfig();
// 设置拦截器
setupRequestInterceptor();
setupResponseInterceptor();
// 构建 API 对象
const APIS = buildApiObject();
export default APIS;示例代码
展开
- api-registry.jsjs
/** * API 注册与检测模块 * from OPS @lixiaopeng used by @henson 2025年7月16日 */ import { requestMethods } from './request'; // 动态导入API模块 const requireModule = require.context('./modules', false, /\.js$/); const modules = requireModule.keys().map((file) => requireModule(file).default); /** * 检查重复API名称 */ export const detectDuplicateApis = () => { const urlNameMap = new Map(); apiList.forEach((api) => { const { name } = api; const apis = urlNameMap.get(name) || []; apis.push(api); urlNameMap.set(name, apis); }); // 两个或以上同名API const duplicates = Array.from(urlNameMap.values()) .filter((apis) => apis.length > 1) .reduce((acc, apis) => acc.concat(apis), []); if (duplicates.length > 0) { console.log('🚨 发现了相同名称的API请及时处理 ==>', { duplicates }); } }; /** * 构建API对象 * @returns {Object} API对象 */ export const buildApiObject = () => { // 检测重复API detectDuplicateApis(); // 构建API对象 return apiList.reduce((apis, api) => { const { name: urlName, type = 'post', url, resType = 'json', timeout = '', repeat = 1 } = api; const requestMethod = requestMethods[type]; //skipCancel用于是否需要跳过取消校验 apis[urlName] = (data, config = { skipCancel: api.skipCancel || false }) => requestMethod(url, data, { repeat, resType, timeout, ...config }); return apis; }, {}); }; export default { apiList, detectDuplicateApis, buildApiObject, }; - request.jsjs
/** * POST请求封装 * @param {string} url - 请求URL * @param {Object} data - 请求参数 * @param {Object} config - 请求配置 * @returns {Promise} - 请求Promise */ export const fetchPost = (url, data, config = {}) => { const { timeout, resType } = config; // 默认请求超过1.5秒显示 loading,长请求使用较长的延迟 const loadingDelay = timeout > DEFAULT_DELAY ? timeout : DEFAULT_DELAY; LoadingInstance.start({}, loadingDelay); // 设置超时时间 axios.defaults.timeout = timeout || axios.defaults.timeout; // 设置响应类型 axios.defaults.responseType = resType || 'json'; return axios.post(url, filterDirty(data), config).then(handleResponse).catch(handleResponseError); //...省略代码... /** * 处理响应数据 * @param {Object} response - 响应对象 */ const handleResponse = (response) => { LoadingInstance.close(); if (!response) return; const { data } = response; // 处理相关状态码 if (data?.code == 2001) { const currentHash = window.location.hash; const redirectPath = currentHash.startsWith('#/') ? currentHash.substring(2, currentHash.indexOf('?') > -1 ? currentHash.indexOf('?') : undefined) : ''; // 获取当前路径 redirectToLogin(redirectPath); // 重定向到登录页面 } else if (data?.code == 8003) { // 清除用户信息 clearLoginInfo(); Message({ type: 'warning', message: i18n.t('fetch_request_1195') }); redirectToLogin(); // 重定向到登录页面 } else if (data?.code == 8004) { setTimeout(() => { console.log('团队切换'); location.reload(); }, 2000); // return Promise.reject(new Error('团队切换')); } return response; }; export default { fetchPost, fetchGet, requestMethods, }; };
结语
- 学无止境,写出优雅的代码,在日常工作中不断提炼和进步的,希望我们能迈向更高的境界
