前端这碗饭,吃到最后其实是在跟“混乱”打架。刚入行那会儿,我写页面像写作文,想到哪儿写到哪儿:按钮点一下,发个请求,弹个提示,顺手再改个颜色,最后把CSS揉进JS里,美其名曰“方便”。结果三个月后需求一变,我盯着编辑器发呆:这段逻辑怎么又在另一个页面出现了?怎么改这里,那里就报错?页面像被反复贴了又撕的便利贴,边角翘起,字迹模糊。后来我意识到,如果不从“拼页面”转向“搭系统”,前端这条路会越走越沉。
一次改版让我真正开始琢磨组件化。公司要做一个中后台,数据表单多得吓人:搜索区、表格、分页、批量操作、状态筛选。每个页面长得像亲戚,长得不一样但骨架相似。我试着把“搜索”抽出来,起初只是复制粘贴改字段,结果字段一多,校验规则、联动逻辑、时间格式全乱套。后来我硬着头皮把搜索当成一块独立积木:输入框只负责输入,校验器负责规则,事件总线负责把结果抛出去。谁要用,拿去就是。改完第一次,我心里咯噔一下:原来改一个输入框的提示文案,不用再翻三四个文件了。

但组件化并不是把代码切得越碎越好。我也走过极端:做了个“带星号的必填提示组件”,结果发现只在两个表单里用,维护成本反而更高。组件像工具,太通用像瑞士军刀,啥都能干但哪都不锋利;太专用像水果刀,好用但只能切苹果。后来我给自己定了个笨办法:先看复用频率,再看变化边界。表格、分页、弹窗、按钮,这些大概率会变,但变化的节奏不同。表格变的是列和状态,分页变的是大小和跳转规则。把变化的部分做成“插槽”或“配置”,不变的部分写成默认实现,页面组装的时候就像搭乐高,哪块松了就换哪块,而不是推倒重来。
设计组件时,我越来越在意“契约”而不是“实现”。比如一个弹窗,我不关心它从左边滑入还是渐变出现,我只关心它什么时候打开、什么时候关闭、结果是什么。用 TypeScript 把这些写清楚,谁用谁心里有底。曾经有个场景,A页面弹窗里要再套弹窗,B页面只要一层。最开始我写死遮罩层级和动画时长,结果嵌套的时候层级打架,动画卡成PPT。后来改成可配置的层级和可替换的动画组件,外层传个参数就行。那一刻我意识到,好的组件像好的接口:不苛求对方怎么做,只说清楚我能给你什么、需要你给我什么。文档、示例、类型定义,这些“无聊”的东西,在协作时比代码还重要。
组件化真正落地,离不开工程和流程的支持。曾几何时,我们靠“眼力”判断能不能复用:一个组件写得好,靠口口相传。后来我把组件放进统一的地方,配上版本、变更日志和示例墙。新人入职第一天就能跑通一个按钮的不同状态,而不是在项目里大海捞针。发布流程也变了:改一个通用组件,不再是“祈祷别出事”,而是走测试、过看板、发版本。页面更新时依赖组件版本,就像搭积木时确认卡扣是否对齐。偶尔还会遇到“为了赶进度直接改页面”的声音,但当回滚成本被摊开来讲,大家慢慢学会克制:短期快一点,长期稳一点。
结语。组件化不是银弹,它解决不了需求不清、节奏混乱或者目标摇摆的问题。但它给了一副骨架,让前端在面对变化时不必每次都脱臼。它让我从一个“页面工人”慢慢变成“系统搭建者”,把时间花在思考结构而不是修补漏洞上。今天回头看,那些被拆解、被组合、被反复打磨的组件,像一块块砖,铺成了我能走得更远的路。前端的世界会继续热闹,框架会变,工具会新,但把复杂变简单、把混乱变有序的思路,不会过时。