2026/4/6 16:14:52
网站建设
项目流程
【Vue3 PropsSlotsComposable】中后台组件复用实战从复用边界到落地选型彻底搞懂组件化架构设计避开过度抽象与维护泥潭 文章目录一、写在前面为什么你会觉得“复用”很乱二、先给结论三种复用方式怎么选选型速查表建议收藏三、基础扫盲三种方式分别是什么1Props组件的“可配置参数”2插槽 Slots组件的“可插拔区域”3组合式函数 Composable抽离“逻辑能力”四、实战选型一个需求三种方式如何配合五、7年前端也容易踩的“习惯坑”六、可落地的团队规范可直接抄到项目规范七、给新手的“傻瓜决策树”八、总结 系列模块导航 组件化设计基础 系列总览同学们好我是 Eugene尤金一名多年中后台前端开发工程师。Eugene 发音 /juːˈdʒiːn/大家怎么顺口怎么叫就好当你能写出规范、可维护的代码后下一个真正的瓶颈就是架构。面对大型项目、复杂业务你是否也会遇到组件越写越乱、重复开发越来越多需求一变全链路改动不知道怎么分层、怎么抽象、怎么设计才能支撑长期迭代想晋升、想带项目却缺少架构思维。这一系列《前端组件化与架构实战》我会继续用大白话 真实业务场景不讲玄学、不啃晦涩源码只教你能落地、能抗复杂项目的架构思路。帮你从「写页面的开发者」真正升级为「能做架构、能带项目、能搞定复杂需求的前端工程师」。一、写在前面为什么你会觉得“复用”很乱很多同学包括工作多年的前端写 Vue3 时都会遇到这几个现象组件越来越“大”一个组件里什么都做同样的逻辑在多个页面复制粘贴看到props、slot、useXxx都能复用但不知道怎么选后期改需求时一改就牵一堆地方心里发慌根因通常不是“不会写代码”而是复用边界没想清楚你到底是在复用“数据配置”、复用“界面骨架”、还是复用“状态逻辑”⬆ 返回目录二、先给结论三种复用方式怎么选先记住一句话Props复用“参数化差异”同一组件不同配置插槽Slots复用“结构占位”父组件决定某块长什么样组合式函数Composable复用“状态 行为逻辑”跨组件共享能力选型速查表建议收藏场景优先方案原因同一组件只是标题、颜色、大小等不同Props成本最低语义清晰组件框架固定但某些区域 UI 经常变化header/footer/itemSlots保留骨架开放局部结构多个组件都要用同一套请求、分页、校验、倒计时等逻辑Composable把逻辑抽离复用最稳定页面差异是“结构 逻辑”都变化大Slots Composable结构交给插槽行为交给组合函数只想省事先“复制一份改改”不建议短期快长期维护成本高⬆ 返回目录三、基础扫盲三种方式分别是什么1Props组件的“可配置参数”你可以把组件想成一个函数props就是函数入参。示例通用按钮组件!-- BaseButton.vue --scriptsetuplangtsinterfaceProps{type?:primary|default|dangerloading?:boolean disabled?:boolean}withDefaults(definePropsProps(),{type:default,loading:false,disabled:false})constemitdefineEmits{(e:click):void}()functiononClick(){emit(click)}/scripttemplatebuttonclassbase-btn:class[base-btn--${type}]:disableddisabled || loadingclickonClickspanv-ifloading加载中.../spanspanv-elseslot按钮/slot/span/button/templatestylescoped.base-btn{padding:8px 14px;border-radius:6px;border:1px solid #ddd;cursor:pointer;}.base-btn--primary{background:#1677ff;color:#fff;border-color:#1677ff;}.base-btn--default{background:#fff;color:#333;}.base-btn--danger{background:#ff4d4f;color:#fff;border-color:#ff4d4f;}button:disabled{opacity:0.6;cursor:not-allowed;}/style使用BaseButtontypeprimaryclicksave保存/BaseButtonBaseButtontypedanger:loadingsubmitting删除/BaseButtonProps 常见坑坑1直接改 propsprops.xxx ...会报错单向数据流需要本地可改副本时用ref(props.xxx)或computed映射坑2不写默认值导致业务处处判空建议withDefaults坑3Boolean 类型传值混乱disabled写成disabledfalse实际是字符串可能被当真值⬆ 返回目录2插槽 Slots组件的“可插拔区域”插槽不是“传值”而是“传模板结构”。示例通用卡片组件结构固定内容可变!-- BaseCard.vue --templatesectionclassbase-cardheaderclassbase-card__headerslotnameheaderh3默认标题/h3/slot/headermainclassbase-card__bodyslot//mainfooterclassbase-card__footerv-if$slots.footerslotnamefooter//footer/section/templatestylescoped.base-card{border:1px solid #eee;border-radius:8px;padding:16px;background:#fff;}.base-card__header{margin-bottom:12px;}.base-card__footer{margin-top:12px;text-align:right;}/style使用BaseCardtemplate#headerdivstyledisplay:flex;justify-content:space-between;h3订单信息/h3span待支付/span/div/templatep订单号20260326001/pp金额199.00/ptemplate#footerBaseButtontypeprimary去支付/BaseButton/template/BaseCard插槽常见坑坑1所有内容都塞插槽会把组件变成“空壳”失去语义边界坑2作用域插槽变量命名混乱建议统一item、row、data等可读命名坑3不知道什么时候用默认插槽什么时候用具名插槽默认插槽主体内容具名插槽header/footer/empty 等语义明确区域⬆ 返回目录3组合式函数 Composable抽离“逻辑能力”组合式函数最适合复用“有状态的行为逻辑”例如搜索、分页、请求加载态、倒计时。示例封装列表请求逻辑useUserList// composables/useUserList.tsimport{ref}fromvueinterfaceUserItem{id:numbername:stringemail:string}interfaceQueryParams{keyword:stringpage:numberpageSize:number}interfaceApiResult{list:UserItem[]total:number}// 模拟请求functionmockFetchUsers(params:QueryParams):PromiseApiResult{returnnewPromise((resolve){setTimeout((){constallArray.from({length:53},(_,i)({id:i1,name:用户${i1},email:user${i1}test.com}))constfilteredall.filter(uu.name.includes(params.keyword))conststart(params.page-1)*params.pageSizeconstendstartparams.pageSizeresolve({list:filtered.slice(start,end),total:filtered.length})},500)})}exportfunctionuseUserList(){constloadingref(false)constlistrefUserItem[]([])consttotalref(0)constqueryrefQueryParams({keyword:,page:1,pageSize:10})asyncfunctionfetchList(){loading.valuetruetry{constresawaitmockFetchUsers(query.value)list.valueres.list total.valueres.total}finally{loading.valuefalse}}functiononSearch(keyword:string){query.value.keywordkeyword query.value.page1fetchList()}functiononPageChange(page:number){query.value.pagepagefetchList()}return{loading,list,total,query,fetchList,onSearch,onPageChange}}页面使用!-- UserListPage.vue --scriptsetuplangtsimport{onMounted,ref}fromvueimport{useUserList}from/composables/useUserListconstkeywordInputref()const{loading,list,total,query,fetchList,onSearch,onPageChange}useUserList()onMounted(fetchList)/scripttemplatedivinputv-modelkeywordInputplaceholder输入用户名搜索/buttonclickonSearch(keywordInput)搜索/buttonpv-ifloading加载中.../pulv-elseliv-foritem in list:keyitem.id{{ item.name }} - {{ item.email }}/li/uldivstylemargin-top:12px;button:disabledquery.page 1clickonPageChange(query.page - 1)上一页/buttonspanstylemargin:0 8px;第 {{ query.page }} 页 / 共 {{ Math.ceil(total / query.pageSize) }} 页/spanbutton:disabledquery.page Math.ceil(total / query.pageSize)clickonPageChange(query.page 1)下一页/button/div/div/templateComposable 常见坑坑1在函数外定义响应式状态导致意外共享每次调用要独立实例就把ref/reactive放在函数内部坑2命名太泛useData、useCommon后期根本不知道干嘛建议业务语义命名useUserList、useCountdown坑3既做数据请求又改 UI 展示细节Composable 负责逻辑UI 细节尽量留在组件层⬆ 返回目录四、实战选型一个需求三种方式如何配合需求做一个“商品列表卡片”模块卡片样式统一每个业务线头部操作区不同列表查询和分页逻辑可复用推荐设计卡片容器BaseCardSlots商品项配置ProductItemProps列表请求逻辑useProductListComposable这就是典型的Props 管参数Slots 管结构Composable 管逻辑比起“一个超级组件全包”这种拆法更稳、更容易维护和测试。⬆ 返回目录五、7年前端也容易踩的“习惯坑”把复用理解成“少写代码”真正目标是“降低变更成本”不是追求抽象炫技过度提前抽象还没出现第二个真实场景就抽一堆BaseXXX组件职责不清组件同时负责请求、权限、UI、埋点最后没人敢改把 slot 当万能胶到处开洞后面无法约束Composable 无边界增长一个usePage500 行逐渐变成“新型大泥球”⬆ 返回目录六、可落地的团队规范可直接抄到项目规范先判断复用类型再选技术方案参数差异优先 Props结构差异优先 Slots行为逻辑复用优先 Composable一个组件只做一层职责展示层组件尽量“纯”减少副作用命名必须有业务语义useOrderSearch优于useCommonLogic默认值和类型声明要完整Props 使用withDefaults TS 接口插槽要有语义边界常用header/body/footer/empty不要无序扩散Composable 输出稳定 API返回字段结构固定避免上层频繁改调用方式⬆ 返回目录七、给新手的“傻瓜决策树”当你准备复用时按这个顺序问自己只是值不同结构不变吗是用props结构某部分需要父组件自定义吗是用slots多个组件都要同一套状态和行为吗是用composable三者都满足一部分组合使用不冲突⬆ 返回目录八、总结Vue3 的复用设计不是三选一而是明确边界后的“各司其职”props解决“同组件参数化”slots解决“结构扩展”composable解决“逻辑沉淀”你会发现基础越扎实越能写出不炫技但很耐用的代码。真正高级的工程能力往往就是每次都做正确、克制、可维护的选择。⬆ 返回目录 系列模块导航 组件化设计基础持续更新中敬请期待 跟着系列慢慢学把技术功底扎扎实实地打牢 系列总览前端体系化学习完全体基础 → 规范 → 架构 → 大厂面试四套系列、百余篇高质量实战文从入门到进阶一站式补齐前端核心能力前端基础实战系列 《前端基础实战JS/TS与Vue体系化扫盲47 篇完整目录 避坑》前端规范实战系列 《JS/TS/Vue 前端规范实战从写对到写优搞定中后台规范落地打造可维护代码40 篇全目录》前端架构实战系列聚焦工程化、性能优化、可维护架构、中后台体系设计持续更新中前端大厂面试系列覆盖高频考点、手写题、项目深挖、简历与面试技巧规划中每个系列完结后都会整理成一篇完整导航文并附上直达链接方便大家按顺序、体系化学习。全套内容持续更新中敬请期待⬆ 返回目录前端的成长路径很清晰会写代码 → 写规范代码 → 做可扩展架构。每一步都是职业晋升的关键台阶。后续我会持续输出组件化、配置驱动、权限架构、工程化、复杂业务实战干货帮你真正建立架构思维在工作与面试中更有竞争力。觉得有用欢迎点赞 收藏 关注不错过每一篇硬核内容。我是 Eugene与你一起从业务走向架构搞定复杂项目我们下篇干货见