Vue.js 生态系统深度探索与项目实战:一个医疗软件Python开发的“叛逃”手记

~马娜
2025-12-15 19:59
阅读 573

上周五晚上十点,我正坐在成都家中阳台上,一边吸着老妈做的红油抄手,一边用 Vim 打开一个刚 fork 的前端仓库。说来你可能不信——我这个写了八年 Python、连 FastAPI 装饰器都能闭眼写的后端老狗,居然在认真研究 Vue 3 的 Composition API。

这事得从去年双11说起。我们公司(一家专注医疗信息化的中型软件企业)接了个新项目:为某三甲医院开发一套全新的患者随访管理系统。UI 部分原本是外包给一个 React 团队做的,结果临近交付前两周,对方团队突然“跑路”——说是主力工程师跳槽去了字节。产品经理小李急得在 Slack 上@我:“老张,你不是会写点 HTML 吗?能不能救个火?”

我:???

我会写 HTML 是因为二十年前用 Dreamweaver 做过个人主页,跟现代前端框架能是一回事吗?但架不住领导画饼+周末加班补贴翻倍,硬着头皮接了下来。于是,我这个 Vim 党,在 PyCharm 都很少打开的人,被迫踏进了 Vue.js 的世界。


为什么选 Vue?而不是继续“舔”React?

说实话,最初我是想直接上 React 的。毕竟 React 在医疗行业里也不少见,而且我们后端用的是 Django + DRF,理论上前后端分离架构下前端框架随便换。但现实很快打了我的脸:

  • 学习曲线:React Hooks 虽然强大,但对一个习惯了同步逻辑、讨厌状态管理爆炸的 Python 程序员来说,useEffect 里套 useReducer 再套 useContext 的嵌套地狱让我一度想回老家种菜。
  • 团队现状:我们公司前端就俩人,一个还在学 TypeScript,另一个主攻小程序。React 生态虽大,但上手成本高,文档又“抽象”。Vue 的选项式 API(Options API)一眼看过去就像配置文件,特别适合我们这种“非专业前端”快速上手。
  • 国内生态友好:尤雨溪是华人,中文文档质量吊打大部分开源项目。Element Plus、Naive UI 这些组件库对国内医疗系统的表单、表格、弹窗需求支持得贼到位——要知道,医生填个随访表单动不动就是 50+ 字段,还要求实时校验、动态联动。

尤其是上次上线时,测试同事报了个 bug:“点击‘保存’按钮没反应。”
我一查控制台,好家伙:TypeError: Cannot read property 'map' of undefined
在 React 里我可能要翻半天 Redux 状态树,但在 Vue 里,直接看 data() 返回的对象结构,五分钟定位到后端返回的 followupItems 字段偶尔是 null 而不是空数组。改一行代码搞定。那一刻,我真的觉得 Vue 对“非前端思维”太友好了。


从零搭建:一个医疗随访系统的 Vue 实战

我们的系统核心功能其实不复杂:医生创建随访计划 → 患者通过小程序接收任务 → 后台管理端查看完成情况。但难点在于交互密集、数据联动强、权限粒度细

技术栈选择(2024年版)

类别 选择 原因
核心框架 Vue 3 (Composition API) 更好的 TypeScript 支持,逻辑复用更灵活
状态管理 Pinia 比 Vuex 简洁太多,模块化天然支持,和 Composition API 天生一对
UI 组件库 Naive UI 设计清爽,TypeScript 友好,暗色模式支持(医生夜班用!)
HTTP 客户端 Axios + 自定义拦截器 统一处理 token 刷新、错误提示
构建工具 Vite 启动快如闪电,热更新秒级响应 —— 再也不用等 Webpack 编译等到睡着了

关键场景:动态表单 + 实时校验

医疗表单最头疼的就是“动态字段”。比如某个随访项如果选了“有并发症”,就要展开一堆子问题。传统做法是 v-if 控制显示,但字段多起来,data 里全是布尔值开关,维护起来像蜘蛛网。

后来我用了 ref + reactive 组合:

// composables/useFollowupForm.ts
import { ref, reactive } from 'vue'

export function useFollowupForm() {
  const form = reactive({
    hasComplication: false,
    complicationDetails: [] as string[],
    bloodPressure: null,
    // ...其他字段
  })

  const rules = computed(() => ({
    bloodPressure: [
      { required: true, message: '请输入血压值' },
      { validator: validateBP, trigger: 'blur' }
    ],
    complicationDetails: form.hasComplication 
      ? [{ required: true, message: '请填写并发症详情', type: 'array' }] 
      : []
  }))

  return { form, rules }
}

在组件里直接解构使用:

<script setup>
import { useFollowupForm } from '@/composables/useFollowupForm'
const { form, rules } = useFollowupForm()
</script>

<template>
  <n-form :model="form" :rules="rules">
    <n-form-item label="是否有并发症" path="hasComplication">
      <n-switch v-model:value="form.hasComplication" />
    </n-form-item>

    <n-form-item v-if="form.hasComplication" label="并发症详情" path="complicationDetails">
      <n-dynamic-tags v-model:value="form.complicationDetails" />
    </n-form-item>
  </n-form>
</template>

这套方案让表单逻辑从模板里剥离出来,测试也好写多了。最关键的是——再也不用在 template 里写三元表达式判断校验规则了!之前看 React 项目里那些 condition ? [rule1, rule2] : [rule3],真的头大。


和 React 的“综合”对比:不是对立,而是互补

我知道肯定有 React 死忠粉要喷:“这不就是把 useState 拆出来封装嘛?” 你说得对,但工程效率不只看技术上限,更看团队认知成本

我们后端团队 6 个人,4 个会 Python,2 个会 Java,没人专职前端。Vue 的文档就像一本写给工程师看的说明书,而 React 文档有时候读起来像哲学论文(Looking at you, Concurrent Mode)。

不过我也承认,React 在大型应用的状态管理、跨平台(RN)上有优势。所以现在我们内部有个“综合策略”:

  • 管理后台、数据密集型页面 → 用 Vue(开发快、调试直观)
  • 患者端 H5 / 小程序 → 用 Taro + React(一套代码多端运行)
  • AI 辅助诊断模块的可视化 → 用 D3 + 原生 JS(性能优先)

说白了,别被框架绑架。就像我最近在啃的《代码人生》这本书里说的:“工具是仆人,不是主人。” (虽然这本书其实是讲算法的,但这句话被我强行挪用来安慰自己转前端的焦虑)


性能优化:别让医生等得想砸键盘

医疗系统最怕卡顿。医生一天要看上百个患者,如果点个按钮要等两秒,他们真的会打电话骂运维。

我们做了几件事:

  1. 路由懒加载

    // router/index.ts
    const FollowupList = () => import('@/views/followup/List.vue')
    

    首屏加载时间从 3.2s 降到 1.1s。

  2. 虚拟滚动:患者列表经常上千条,用 vue-virtual-scroller 后内存占用降了 70%。

  3. 防抖搜索:医生输患者姓名时,用 lodash.debounce 避免疯狂请求后端。

  4. 生产构建分析

    vite build --report
    

    发现 Element Plus 全量引入占了 1.8MB!立刻改成按需引入:

    // vite.config.ts
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
    
    export default defineConfig({
      plugins: [
        vue(),
        AutoImport({ imports: ['vue'] }),
        Components({
          resolvers: [NaiveUiResolver()]
        })
      ]
    })
    

上线后 Lighthouse 分数从 68 提到 92,运维小哥终于不用半夜被 PagerDuty 叫醒了。


调试技巧:Vim 党的前端生存指南

作为一个拒绝 VS Code 的 Vim 党,我摸索出一套“极简前端调试法”:

  • 浏览器 DevTools + console.log:别笑,真香。Vue 3 的 <script setup> 里变量可以直接在 console 里访问(配合 expose)。
  • Vue Devtools 插件:必须装!能直接看组件树、Pinia 状态、事件流。比 React Devtools 更直观(个人观点)。
  • Vite 的 HMR 日志:热更新失败时,终端会明确告诉你哪个模块没更新成功,不用瞎猜。
  • v-memo 优化列表:当列表项有复杂计算时,加上这个指令能避免无效重渲染。

最骚的操作是我把 .vimrc 配了自动补全 Vue 模板语法:

autocmd FileType vue setlocal omnifunc=vsnip#complete

虽然比不上 IDE,但至少 <template> 里敲 div. 能自动补成 <div class=""></div> —— 老程序员的倔强罢了。


写在最后:代码人生,不止一种活法

现在回头看,从被逼上梁山到主动拥抱 Vue,这段经历让我意识到:所谓“全栈”,不是什么都会,而是知道什么时候该用什么工具解决问题

上周产品又提了个需求:“能不能加个 AI 自动生成随访建议的功能?” 我一边在 Jupyter Notebook 里跑 BERT 模型,一边在 Vue 组件里调用后端接口展示结果。那一刻,Python 和 Vue 的代码在我屏幕上交相辉映,突然觉得——这不就是《代码人生》里描绘的理想状态吗?技术没有高低贵贱,只有是否合适。

当然,如果产品经理再敢让我改 UI 配色(上次非要从蓝色改成“医患和谐绿”),我可能真的会提离职去卖火锅底料。毕竟在成都,生活节奏舒服,但底线不能丢啊。


P.S. 如果你也是后端转前端的苦命人,推荐两本书:

  • 《Vue.js 设计与实现》——霍春阳写的,深入浅出,讲透响应式原理
  • 《代码人生》——虽然书名鸡汤,但第 7 章讲“技术选型的心理陷阱”简直是我的嘴替

共勉。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝