1483 字
4 分钟
Vue3 前端架构重构实践
Vue3 前端架构重构实践:从双端分离到统一响应式组件
概述
本文将详细介绍一个基于 Vue3 + TypeScript 的前端项目重构过程。通过一系列系统性的重构,我将原本分离的双端代码整合为统一的响应式组件,大幅提升了代码可维护性和开发效率。
重构背景
在重构之前,项目采用传统的双端分离架构:
- 桌面端组件:Home.vue、Device.vue、Data.vue 等
- 移动端组件:MobileHome.vue、MobileDevice.vue、MobileData.vue 等
这种架构存在以下问题:
- 代码重复:相同功能需要在两个组件中分别实现
- 维护困难:修复bug或添加功能需要修改多处代码
- 一致性差:双端界面风格和行为难以保持一致
- 开发效率低:新功能开发需要编写两套代码
重构阶段详解
阶段一:统一API层重构
主要变更:
- 创建统一API层 src/utils/api.ts
- 封装请求/响应拦截器
- 替换所有组件中的 fetch 调用为 api.ts 方法
- 实现统一错误处理和token刷新逻辑
技术实现:
import { ElMessage } from'element-plus';import router from '@/router';
const BASE_URL = '';
// 请求拦截器const requestInterceptor = (config:RequestInit) => { const token = localStorage.getItem ('accessToken'); const headers = new Headers(config. headers);
if (token) { headers.set('Authorization', `Bearer ${token}`); } headers.set('Accept', 'application/ json');
return { ...config, headers, credentials: 'include' as RequestCredentials };};
// 响应拦截器const responseInterceptor = async(response: Response) => { if (response.status === 401) { // 处理401错误 localStorage.removeItem ('accessToken'); localStorage.removeItem ('refreshToken'); localStorage.removeItem ('isAuthenticated'); localStorage.removeItem('username'); localStorage.removeItem('role'); window.dispatchEvent(new Event ('loginStatusChanged')); ElMessage.error('登录已过期,请重新登录 '); router.push('/Login'); throw new Error('Unauthorized'); }
if (!response.ok) { const error = await response.json(). catch(() => ({})); throw new Error(error.detail || error.msg || '请求失败'); }
return response.json();};
// 统一请求方法export const api = { async get<T = any>(url: string, params?: Record<string, any>): Promise<T> { let fullUrl = BASE_URL + url; if (params) { const searchParams = new URLSearchParams(); Object.entries(params).forEach (([key, value]) => { if (value !== undefined && value !== null) { searchParams.append(key, String(value)); } }); fullUrl += `?${searchParams. toString()}`; }
const config = requestInterceptor({ method: 'GET' }); const response = await fetch (fullUrl, config); return responseInterceptor (response); },
async post<T = any>(url: string, data? : any, options?: { headers?: Record<string, string> }): Promise<T> { const headers: Record<string, string> = options?.headers || { 'Content-Type': 'application/ json' }; const config = requestInterceptor({ method: 'POST', headers, body: data ? (headers ['Content-Type'] === 'application/ json' ? JSON.stringify(data) : data) : undefined });
const response = await fetch (BASE_URL + url, config); return responseInterceptor (response); },
async put<T = any>(url: string, data? : any): Promise<T> { const config = requestInterceptor({ method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: data ? JSON.stringify(data) : undefined });
const response = await fetch (BASE_URL + url, config); return responseInterceptor (response); },
async delete<T = any>(url: string): Promise<T> { const config = requestInterceptor({ method: 'DELETE' }); const response = await fetch (BASE_URL + url, config); return responseInterceptor (response); }};优化效果:
- 14个文件被修改,代码量减少约850行
- 统一了所有API调用的错误处理逻辑
- 实现了自动token刷新和登录状态管理
- 消除了重复的网络请求代码
阶段二:整合双端总览组件(Commit: c98cec87)
主要变更:
- 整合 Home.vue 和 MobileHome.vue 为单一组件 HomePage.vue
- 清理无用文件:FullscreenMode.vue、Old_Home.vue
- 优化文件结构
技术实现要点:
<template> <div :class="['home-container', { 'mobile': isMobile }]"> <!-- 根据设备类型渲染不同布局 --> <div v-if="!isMobile" class="desktop-layout"> <!-- 桌面端布局 --> </div> <div v-else class="mobile-layout"> <!-- 移动端布局 --> </div> </div></template>
<script setup>import { computed } from 'vue';
const isMobile = computed(() => { return window.innerWidth < 768 || / Android|webOS|iPhone|iPad|iPod| BlackBerry|IEMobile|Opera Mini/i.test (navigator.userAgent);});</script>关键优化:
- 文件数量从6个减少到5个
- 代码量减少约1274行
- 实现了真正的响应式布局
阶段三:整合双端设备界面组件(Commit: 94572906)
主要变更:
- 创建统一的 DevicePage.vue 组件
- 删除 Device.vue 和 MobileDevice.vue
- 更新路由配置
技术挑战: 设备管理界面功能复杂,包含:
- 设备列表展示
- 设备添加/编辑/删除
- 设备状态监控
- 批量操作功能
解决方案: 使用条件渲染和响应式布局策略:
<template> <div class="device-page"> <!-- 桌面端:表格视图 --> <el-table v-if="!isMobile" :data="devices"> <!-- 表格列定义 --> </el-table>
<!-- 移动端:卡片列表视图 --> <div v-else class="mobile-device-list"> <div v-for="device in devices" :key="device.id" class="device-card"> <!-- 卡片内容 --> </div> </div> </div></template>阶段四至六:登录、注册、个人信息界面整合
登录界面
- 整合 Login.vue 和 MobileLogin.vue 为 LoginPage.vue
- 代码量减少约180行
注册界面
- 整合 Register.vue 和 MobileRegister.vue 为 RegisterPage.vue
- 代码量减少约82行
个人信息界面
- 整合 Profile.vue 和 MobileProfile.vue 为 ProfilePage.vue
- 代码量减少约476行
共同的技术特点:
- 使用 v-if=“!isMobile” 进行条件渲染
- 表单布局自适应:桌面端水平排列,移动端垂直堆叠
- 统一的状态管理和表单验证逻辑
阶段七:用户管理界面整合
主要变更:
- 整合 UserManage.vue 和 MobileUserManage.vue
- 优化用户列表展示和权限管理功能
技术细节:
- 桌面端使用 Element Plus 的 el-table 组件
- 移动端使用自定义卡片列表
- 统一的用户状态管理和权限控制
阶段八:备案信息组件整合
主要变更:
- 删除独立的 MobileBeian.vue 组件
- 将备案信息逻辑整合到 MobilePage.vue 中
- 简化组件层级
阶段九:数据管理组件重构
这是最复杂的重构之一,涉及:
- 删除 MobileData.vue(1534行)
- 重构 Data.vue 为响应式统一组件
- 支持实时监控、数据分析、历史数据查询
技术亮点:
- 平台检测:
const shouldUseMobilePage = () => { const width = window.innerWidth; const isMobileDevice = /Android|webOS| iPhone|iPad|iPod|BlackBerry|IEMobile| Opera Mini/i.test(navigator. userAgent); return width < 768 || isMobileDevice;};- 差异化数据展示:
// 桌面端显示24小时数据,移动端显示6小时数据const timeRange = computed(() =>isMobile.value ? 6 : 24);- 移动端图表优化:
// 移动端图表数据采样12个点优化显示const chartData = computed(() => { const data = rawData.value; if (isMobile.value && data.length > 12) { // 采样处理 const step = Math.ceil(data. length / 12); return data.filter((_, index) => index % step === 0); } return data;});- 历史数据展示差异化:
<!-- 桌面端:表格 --><el-table v-if="!isMobile":data="historyData"> <!-- 表格列 --></el-table>
<!-- 移动端:卡片列表 --><div v-else class="history-cards"> <div v-for="item in historyData" :key="item.id" class="history-card"> <!-- 卡片内容 --> </div></div>重构成果总结
代码量变化
| 重构阶段 | 修改文件数 | 代码变化 |
|---|---|---|
| API层重构 | 14 | -850行 |
| 总览组件整合 | 6 | -1274行 |
| 设备界面整合 | 5 | -389行 |
| 登录界面整合 | 4 | -180行 |
| 注册界面整合 | 5 | -82行 |
| 个人信息整合 | 4 | -476行 |
| 用户管理整合 | 3 | -631行 |
| 备案信息整合 | 8 | -20行 |
| 数据管理整合 | 3 | -513行 |
总计:代码减少约 4415 行
架构优化收益
- 维护性提升:相同功能只需维护一份代码
- 一致性保证:双端界面风格和行为完全一致
- 开发效率:新功能开发工作量减少约50%
- Bug修复:修复一个问题只需修改一处代码
- 性能优化:减少了重复代码的加载和执行
关键技术方案
- 响应式检测设备类型:
const isMobile = computed(() => { return window.innerWidth < 768 || /Android|webOS|iPhone|iPad|iPod| BlackBerry|IEMobile|Opera Mini/i. test(navigator.userAgent);});- 条件渲染策略:
<template> <div v-if="!isMobile" class="desktop-view"> <!-- 桌面端特定内容 --> </div> <div v-else class="mobile-view"> <!-- 移动端特定内容 --> </div></template>- 差异化配置:
const config = computed(() => ({ pageSize: isMobile.value ? 10 : 20, chartPoints: isMobile.value ? 12 : 24, showDetail: !isMobile.value}));遇到的挑战及解决方案
挑战1:功能差异处理
问题:某些功能在桌面端和移动端表现不同
解决方案:
- 使用 computed 属性动态计算配置
- 保留核心逻辑一致,仅UI层差异化
挑战2:性能优化
问题:移动端数据量大时性能下降
解决方案:
- 移动端数据采样(如历史数据只显示12个点)
- 使用 v-memo 和 v-once 优化渲染
- 懒加载非关键组件
挑战3:样式冲突
问题:双端样式混合可能产生冲突
解决方案:
- 使用 BEM 命名规范
- 添加平台特定类名前缀
- CSS 模块化
总结
通过这次系统性的重构,我们成功将一个双端分离的代码库转变为现代化的响应式架构。关键经验包括:
- 先统一基础设施:API层的统一是后续组件整合的基础
- 渐进式重构:分阶段进行,每个阶段都有明确目标
- 保持功能完整:每次重构后都进行完整测试
- 代码复用优先:提取公共逻辑,减少重复代码
部分信息可能已经过时









