在前端开发中,经常面临这样的情况:随着功能不断增加,组件变得越来越庞大,代码越来越难以维护。本文将分享一个真实的交通网络路径查询组件重构案例,从单一文件组件到基于组合式API的模块化架构的演进过程,并探讨这种重构的影响、利弊以及组合式API在其中发挥的作用。
重构前,station-display.vue
组件接近900行代码,包含了查询表单、路径结果展示、站点可视化等多个功能模块。这种"大而全"的组件存在以下问题:
以下是重构前的部分代码结构:
...
...
为了解决上述问题,采用了基于组合式API的模块化架构进行重构:
src/views/flow-dispatch/interrupt-path-search/
├── components/
│ ├── station-display.vue # 主组件(精简版)
│ ├── station-display/ # 子组件目录
│ │ ├── MetroQueryForm.vue # 查询表单组件
│ │ ├── PathResultItem.vue # 路径结果项组件
│ │ └── StationVisualization.vue # 站点可视化组件
├── composables/ # 组合式API目录
│ ├── useMetroPathData.ts # 路径数据处理逻辑
│ └── useMetroQuery.ts # 查询逻辑
重构后的主组件 station-display.vue
变得简洁明了:
路径查询
以 useMetroQuery.ts
为例,它封装了查询相关的状态和逻辑:
// useMetroQuery.ts
import { ref, computed, Ref } from 'vue';
import { useMetroStore } from '@/store';
import api from '../components/api';
// 类型定义
export interface MetroLine {
value: string;
label: string;
stations?: MetroStation[];
}
export interface MetroStation {
value: string;
label: string;
lineId: string;
}
export interface QueryParams {
fromLineId: string;
fromStationId: string;
toLineId: string;
toStationId: string;
interrupts: any[];
}
// 组合式函数
export function useMetroQuery(emit: any, interruptsRef: Ref<any[]>) {
// 状态定义
const startLine = ref('');
const startStation = ref('');
const endLine = ref('');
const endStation = ref('');
const renderKey = ref(0);
const pathResults = ref([]);
const selectedPathIndex = ref(0);
const metroStore = useMetroStore();
// 计算属性
const loading = computed(() => metroStore.loading);
const canQuery = computed(() => {
// 查询条件验证逻辑
return !!startLine.value && !!startStation.value &&
!!endLine.value && !!endStation.value;
});
// 更多计算属性...
// 方法定义
const fetchStationsAndUpdateModel = async (type, lineId) => {
// 获取站点数据的逻辑
};
const handleQuery = async () => {
// 查询逻辑
};
const selectPath = (index) => {
// 选择路径逻辑
};
const initData = async () => {
// 初始化逻辑
};
// 返回状态和方法
return {
startLine, startStation, endLine, endStation,
renderKey, loading, pathResults, selectedPathIndex,
canQuery, availableLines, startLineStations, endLineStations,
fetchStationsAndUpdateModel, handleQuery, selectPath, initData
};
}
文件 | 重构前 | 重构后 | 变化 |
---|---|---|---|
station-display.vue | ~900行 | ~150行 | -83% |
总代码量 | ~900行 | ~600行 | -33% |
虽然总代码量只减少了约33%,但代码被合理地分散到多个文件中,每个文件都更加专注和简洁。
功能模块 | 重构前 | 重构后 |
---|---|---|
查询表单 | 内嵌在主组件中 | 独立组件 MetroQueryForm.vue |
路径结果展示 | 内嵌在主组件中 | 独立组件 PathResultItem.vue |
站点可视化 | 内嵌在主组件中 | 独立组件 StationVisualization.vue |
路径数据处理 | 内嵌在主组件中 | 独立API useMetroPathData.ts |
查询逻辑 | 内嵌在主组件中 | 独立API useMetroQuery.ts |
watchEffect
替代 watch
,减少不必要的监听在本次重构中,并未陷入过度优化或过度封装的陷阱,原因如下:
组合式API是Vue 3引入的一种新的代码组织方式,它在此次重构中发挥了关键作用:
本次重构将一个庞大的单文件组件转变为基于组合式API的模块化架构,大大提高了代码的可读性、可维护性和可复用性。虽然重构需要一定的时间和精力,但从长远来看,这种投资是值得的,它为后续的功能开发和维护奠定了坚实的基础。
组合式API作为Vue 3的核心特性,为提供了一种更灵活、更强大的代码组织方式。在本次重构中,它帮助实现了关注点分离和逻辑复用,是重构成功的关键因素之一。
最后,重构不是目的,而是手段。的目标是创建更好的代码,使其更容易理解、维护和扩展。在这个过程中,需要保持平衡,避免过度优化和过度封装,始终以解决实际问题为导向。
基于此次重构的经验,计划在未来的项目中更广泛地应用组合式API和模块化架构。同时,也将继续探索更好的代码组织方式,如自动化测试、文档生成等,进一步提高代码质量和开发效率。