尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
vue-vben-admin 为什么用 provide/inject 替代 props 穿透?3 个设计模式拆解
vue-vben-admin 为什么用 provide/inject 替代 props 穿透3 个设计模式拆解【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin你复制了 5 个几乎一样的表单弹窗每次加字段都要翻 5 遍代码vue-vben-admin 的答案是把表单、弹窗这类高频复用的 UI 零件拆成原子组件再用一个 API 对象 跨层通信把零件拼成业务页面。本文带你从源码层面看这套先拆、再通、后拼的组合式组件库设计。场景一零件的边界——Form、FormField、Modal 各自只管一件事表单只负责整表交互表单入口 vben-use-form.vue 不渲染任何具体输入框它只处理三件整表级的事转发 props、渲染默认操作按钮、拦截回车提交。function handleKeyDownEnter(event: KeyboardEvent) { if (!state?.value.submitOnEnter || !forward.value.formApi?.isMounted) { return; } // 如果是 textarea 不阻止默认行为否则会导致无法换行。 if (event.target instanceof HTMLTextAreaElement) { return; } event.preventDefault(); forward.value.formApi?.validateAndSubmit(); }字段组件只渲染一个输入框单个字段由 form-field.vue 负责它的边界清晰到只处理一件事把component: Input这样的配置解析成真实组件并挂上自己的错误状态。const FieldComponent computed(() { const finalComponent isString(component) ? componentMap.value[component] : component; if (!finalComponent) { // 组件未注册 console.warn(Component ${component} is not registered); } return finalComponent ? markRaw(toRaw(finalComponent)) : finalComponent; });注意它对未注册组件只打警告不抛错——schema 是声明式配置写错组件名时页面应该能继续渲染其他字段而不是整表崩掉。弹窗组件只管壳子modal.vue 不关心内容是什么表单还是富文本它只负责打开/关闭、锁定、loading 这些壳子状态全部交给ModalApi管理。const [Modal, modalApi] useVbenModal({ async onConfirm() { modalApi.close(); }, });如果没有这层切分一个带校验、带按钮、可回车的表单至少 300 行拆开后每个文件都能独立测试form-ui 包里就有 15 个__tests__文件对着不同切片验证。场景二状态怎么流转——API 对象 provide/inject每个组件配一个API 对象当状态中枢这是整个组件库最核心的设计useVbenForm和useVbenModal都不直接返回 DOM而是返回[组件, api]二元组。api 内部是一个响应式 storesetState、close、validate都收口在它身上。export function useVbenForm(options: VbenFormPropsany, any, any, any) { const api new FormApiany, any, any, any(options); const extendedApi api as ExtendedFormApiany, any, any, any; extendedApi.useStore (selector: any) { return useSelector(api.store, selector); }; const Form defineComponent((props, { attrs, slots }) { api.setState({ ...props, ...attrs }); return () h(VbenUseForm, { ...props, ...attrs, formApi: extendedApi }, slots); }, { name: VbenUseForm, inheritAttrs: false }); return [Form, extendedApi] as const; }摘自 use-vben-form.ts这样业务代码里formApi.validate()、modalApi.open()和组件本身是同一个响应式数据源不存在命令式 ref 和声明式 state 不同步的经典问题。用 provide 干掉 props 穿透字段组件离表单根组件隔了好几层如果靠 props 一层层传formApi每加一层渲染都要改三处代码。项目用 provide/inject 解决vben-use-form.vue 里只有两行注入provideFormProps([forward, form]); provideComponentRefMap(componentRefMap);子层任何深度都能取回const formRenderProps injectRenderFormProps(); const formApi formRenderProps.form; if (!formApi) { throw new Error(Form api is required in FormField /); }数据流向一句话描述状态在 API 对象向上子组件调 api 方法触发能力在 context向下根组件 provide任意层级 inject。props/emit 只保留给同层组件之间的直接协作比如 Form 把keydown.enter事件抛给外层处理。想看完整实现顺着 form-render/context.ts 和 use-form-context.ts 读即可。场景三组合出真实页面——弹窗里放一张表单以编辑用户信息为例页面只需要做两件事Modal 打开时回填表单、提交成功后关闭弹窗。两个组件互不知道对方的存在script setup langts import { useVbenForm, useVbenModal } from vben/common-ui; const [Modal, modalApi] useVbenModal({ async onOpenChange(isOpen: boolean) { if (isOpen) { const data modalApi.getData(); await formApi.setValues(data); // 打开即回填 } }, }); const [Form, formApi] useVbenForm({ schema: userSchema }); // 内部逻辑已封装此处省略 /script template Modal Form submittedmodalApi.close() / /Modal /template这个组合模式在 form-modal-demo.vue 里有完整可运行版本。组合优于修改源码落下来就是三条组件之间不直接引用只通过各自的 api 和 context 协作替换任何一半都不影响另一半业务差异回填、校验规则、提交接口写在页面这一层源码层永远保持不知道业务新需求优先查 schema 配置和插槽动源码前先看__tests__里有没有对应的兼容约束。避坑与进阶源码里写明的三个陷阱症状schema 里组件名拼错页面不报错原因form-field.vue 对未注册组件只console.warn不抛错设计如此。正确做法在 config.ts 的COMPONENT_MAP里确认组件名或自定义组件时通过componentMapprop 补注册别指望运行时帮你兜底。症状Modal 的 title 改了没生效原因当你用connectedComponent把 Modal 抽成独立文件后壳子上的 props 会被 use-modal.ts 显式警告拦截——When connectedComponent exists, do not set props。正确做法改状态一律走modalApi.setState({ title })而不是往Modal标签上挂属性。进阶利用内置防抖写即改即存表单值监听已经内置了防抖提交无需自己套 lodashconst handleValuesChangeDebounced useDebounceFn(async () { state?.value.submitOnChange forward.value.formApi?.validateAndSubmit(); }, state?.value?.changeDebouncedTime ?? 300);vben-use-form.vue 第 75~77 行打开submitOnChange即可获得改完 300ms 自动校验提交的行为changeDebouncedTime可配置——实时搜索类场景直接复用别重复造防抖。接着往哪走下一步你可以自己走读三个地方把这条线串起来表单原子层的 packages/core/ui-kit/form-ui/、弹窗组合层的 packages/core/ui-kit/popup-ui/以及能跑起来的组合示例 playground/src/views/examples/modal/。读完 demo 再回看__tests__里的 form-integration 测试你会更清楚这套拆—通—拼的设计在哪些边界上被反复验证过。【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

react-admin 软删除实战:深入掌握 `<DeletedRecordsList>` 组件

react-admin 软删除实战:深入掌握 `<DeletedRecordsList>` 组件

react-admin 软删除实战&#xff1a;深入掌握 <DeletedRecordsList> 组件 【免费下载链接】react-admin A frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design 项目地址: https://gitcode.co…

📅 2026/9/20 10:59:42
Sandboxie 开源项目贡献指南:从证书体系、代码提交到沙盒问题排查的完整协作工作流

Sandboxie 开源项目贡献指南:从证书体系、代码提交到沙盒问题排查的完整协作工作流

Sandboxie 开源项目贡献指南&#xff1a;从证书体系、代码提交到沙盒问题排查的完整协作工作流 【免费下载链接】Sandboxie Sandboxie Plus & Classic 项目地址: https://gitcode.com/gh_mirrors/sa/Sandboxie Sandboxie Plus / Classic 是一款面向 Windows NT 系列…

📅 2026/9/20 10:59:42
QQ空间备份教程:5 分钟扫一次码,历史说说 Excel+网页全量导出

QQ空间备份教程:5 分钟扫一次码,历史说说 Excel+网页全量导出

QQ空间备份教程&#xff1a;5 分钟扫一次码&#xff0c;历史说说 Excel网页全量导出 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 翻回 2014 年的说说&#xff0c;网页版要点几千次&q…

📅 2026/9/20 10:59:42
MORE NEWS

更多资讯

📰

BrewUI:为Homebrew打造可视化操作台,让包管理更直观

我先交代一下背景&#xff1a;这个项目最开始跟大多数人的需求一样&#xff0c;单纯就是“不想每次都在终端里敲 brew install、brew update、brew upgrade 这一串命令”。Homebrew 本身就是 macOS 上最流行的包管理器&#xff0c;用过的人都知道它有多强大&#xff0c;但它的操…

📰

BrewUI:给Homebrew装上图形化仪表盘,让包管理更直观

你有没有过这种经验&#xff1a;在终端里敲了一行brew upgrade&#xff0c;然后盯着满屏滚动的依赖日志发呆&#xff0c;不确定这次升级到底动了多少东西、等多久、会不会翻车。Homebrew本身是个好工具&#xff0c;但它的信息输出确实不够“友好”&#xff0c;尤其对刚接触 mac…

📰

grok-build 认证体系全解:浏览器登录、企业 OIDC、设备码与外部认证提供方

人工智能AI 应用AI Agent代码智能体开发工具CLIMCP Clients 【免费下载链接】grok-build SpaceXAIs coding agent harness and TUI. Fullscreen, mouse interactive, extensible. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/gr/grok-build 点击查看 免费下载 本篇指…

📰

随机子空间集成:原理、与随机森林的区别及scikit-learn实操

做分类任务最怕什么&#xff1f;不是模型不收敛&#xff0c;也不是代码崩了&#xff0c;而是模型给出的预测结果“飘”。之前做特征维度上百的物料分类&#xff0c;单棵决策树效果一般&#xff0c;试了 Bagging 之后稳了一些&#xff0c;但总觉得基学习器彼此太像&#xff0c;预…

📰

Kotlin协程挂起函数原理:CPS变换与状态机的字节码拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

BrewUI 使用指南:给 macOS 的 Homebrew 配一个好用的图形界面

1. 为什么我给 Homebrew 配了一个图形界面用 macOS 开发的同学&#xff0c;几乎绕不开 Homebrew 这个包管理器。日常装个 nginx、redis、ffmpeg&#xff0c;一条brew install xxx就搞定&#xff0c;数据基本都沉淀在/opt/homebrew&#xff08;Apple Silicon&#xff09;或者/us…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬