(💰TRAE SOLO实战赛强势上线,速戳上图
了解详情🔍)
前言
朋友们好啊,我是 auto-plugin 掌门人德莱厄斯。
刚才有个朋友问我,德老师发生什么事了,我说怎么回事,给我发了几张截图,我一看,嗷!原来是昨天,有两个小项目,两三个页面,一个只有表单收集页,一个是登录页加信息页。他们说,唉... 有一个说是他不想在这种小项目中引入大型组件库,徳老师你能不能教教我 auto 功法,哎帮助开发一下,我的小项目。我说可以,我说你老用组件库大力出奇迹,不好用,他不服气。我说小朋友,你一个组件库来用在我 vue 和 react 上,他说用不了。他说你这也没用。我说我这个有用,这是统一,传统开发是讲究一次编译到处运行。二百个组件的大型组件库,掰不动我这一个小组件。
啊... 哈,他非和我试试,我说可以。哎... 我一说啪一下就给 element-plus 引入了,很快啊!然后上来就是一个 message,一个 tooltip,一个响应式布局。我全部防出去了啊,防出去以后,自然是传统开发点到为止,autohue 藏在 github 没给他看。我笑一下准备上班。由于这时间,按传统开发的点到为止他已经输了,如果 autohue 发力,一下就把他组件库打散架了,放在 github 没给他看,他也承认,说组件库没有这种功能。啊,我收手的时间不聊了,他突然袭击说 dialog 你没有,啊,我大意了啊,没有做。哎,他的 dialog 给我脸打了一下,但是没关系啊!他也说,啊他截图也说了,两分多钟以后,当时流眼泪了,捂着眼说,我说停停。然后两分钟以后,哎两分钟以后就好了,我说小伙子你不讲武德你不懂,说徳老师对不起对不起,我不懂规矩。啊,他说他是乱打的,他可不是乱打啊,mmessage、tooltip 训练有素,后来他说他练过两年开源,啊,看来是有备而来。这两个年轻人不讲武德,来骗,来偷袭!我 26 岁的老同志,这好吗这不好,我劝!这位年轻人耗子尾汁,好好反思,以后不要再犯这样的聪明,小聪明啊。啊,呃... 开发要以和为贵,讲究统一,不要搞窝里斗,谢谢朋友们。
dialog 的场景往往出现在表单收集、确认问询的场景,在 JQ 时代,我们可能很常用浏览器自带的 alert,但是这东西会阻塞主进程,且样式也不太好控制,或者用 bootstrap 的组件。到了框架时代,出现了各种组件库,但是它们都存在几个问题
-
要用必须全量安装(虽然现在大家都支持树摇)
-
修改样式比较麻烦
-
不支持跨框架,感知不统一
他们跟自身生态、框架生态深度绑定,虽然大多数时候我们用起来很方便,心智负担也很低。但是他们不可避免地出现了上述三个问题。
那么如果像我刚才提到的,只做一两个页面的简单应用,也要引入组件库吗,要是引入组件库,你还要画两分钟思考一下,你要用 vue 生态还是 react 生态的。那有人说了,现在组件库也是跨框架支持啊,下载对应的包就行了,但是你看,截至目前 2025 年 10 月 28 日,ant-design 的 vue 版本还停留在 4.26 ,而 react 版本已经到了 5.27.6(BTW:antd for react 组件库现在已支持 autofit.js)。容易发现,使用不同的框架,即使是同一个组件库,不同框架开发体验也是不同的。
这在多元化我们的选择的同时,也割裂了开发的生态。
碰巧我最近又在写一个简单项目,需要一个 dialog 组件,我又讨厌原子化 css 的写法(这就是为什么不直接用 shadcn 的原因),怎么办呢,再实现一个得了。
autodialog.js
github:
GitHub - Auto-Plugin/autodialog.js
我取名可不是瞎取的(也瞎取过),这个 autodialog.js 是真正的框架无关的 dialog 组件。那么它的 auto 体现在哪呢?它可以自动识别传入的弹窗内容是来自什么框架!甚至不会破坏 vue 的响应式和 react 的状态,你甚至可以在 原生 html、svelte、solid、augular 中无缝使用,而不破坏框架本身的特性。更惊奇的是,
「调用方法是一模一样的」
。
在说实现思路之前,我想让你先感受一下 autodialog.js 的使用
快速使用示例
原生 HTML
import autodialog from 'autodialog.js'autodialog.show('<div>Hello World!</div>')
Vue 3
import autodialog from 'autodialog.js'import MyDialog from './MyDialog.vue'autodialog.show(MyDialog, { props: { title: '你好 Vue' })
React 18+
import autodialog from 'autodialog.js'import MyDialog from './MyDialog.tsx'autodialog.show(MyDialog, { props: { message: '你好 React' }})
666 有没有?autodialog.js 内部自动判断了传入的组件类型,使无论什么框架的调用方式都完全一致!
而且除了遮罩和最简单的动画外(当然也提供了自定义方式),其余样式完全由你的内容决定!你完全无需写多层选择器或者使用
!important
来覆盖样式。
原理解析
要实现这种跨框架,又保留框架特性,又保持感知统一的工具库,其实有一条成熟且稳妥的道路,那就是
适配器(adapter)
autodialog.js 也是这样,它的 core 包是纯 js 的,但是接受各种各样的适配器,我定义的适配器格式如下:
/** * 适配器接口 * - render: 渲染内容到 panel 上 * - unmount: 卸载 panel 上的内容(可选) */export interface Adapter { render: (content: any, options: { container: HTMLElement; panel: HTMLElement;[key: string]: any }) => void unmount?: (panel: HTMLElement) => void}
比如要实现一个 vue 的适配器就是这样:
import { createApp, h, type Component } from 'vue'interface VueRenderOptions { panel: HTMLElement title?: string props?: Record<string, any> onClose?: () => void}export const VueAdapter = { render(Component: Component, { panel, title, props = {}, onClose }: VueRenderOptions) { // 创建一个 Vue 应用实例 const app = createApp({ render() { return h('div', { class: 'autodialog-vue-wrapper' }, [ title ? h('div', { class: 'autodialog-header' }, title) : null, h(Component, { ...props, onClose }), ]) }, }) // 挂载到 panel app.mount(panel) ;(panel as any)._vueApp = app }, unmount(panel: HTMLElement) { const app = (panel as any)._vueApp if (app) { app.unmount() delete (panel as any)._vueApp } },}
当然,autodialog.js 已经内置了 vue 和 react 的适配器。
如果你使用 svelte,autodialog.js 没有内置,那么你可以使用适配器注册器函数来外部挂载一个适配器,像下面的章节(进阶使用)里就实现了一个 svelte 适配器。
你完全不必担心适配器很难写,因为你使用你熟悉的框架,如果你熟悉 vue,那么看一下上面的 vue 适配器,它也只是使用了 vue 的 render 和 h 函数。
在 autodialog.js 的 core 中,是这样自动判断内容来自什么组件,该用什么适配器的:
/** * 自动检测逻辑(detect 不强制 */ private detectAdapter(content: any): Adapter { // 1️⃣ 优先使用用户注册的自定义适配器 for (const { detect, adapter } of Dialog.customAdapters) { try { // detect 可省略:省略则直接匹配 if (!detect || detect(content)) return adapter } catch { } } // 2️⃣ 内置适配器兜底 if (typeof content === 'string' || content instanceof HTMLElement || content instanceof DocumentFragment) return HtmlAdapter if (content && (typeof content === 'object' || typeof content === 'function')) { const proto = (content as any).prototype const hasSetup = !!(content as any).setup const hasRender = !!(content as any).render const isClass = proto && proto.isReactComponent const isFunctionComponent = typeof content === 'function' && /^[A-Z]/.test(content.name) if (hasSetup || hasRender) return VueAdapter if (isClass || isFunctionComponent) return ReactAdapter } throw new Error('[autodialog] Unsupported component type.') }
内置的 vue 和 react 适配器是直接检查了各自组件对象的特征,从而实现自动拾取适配器,自定义适配器则要写一个 detect 函数(特征检查),当然这不是必须的,因为你在你的框架中只会有一种组件传入,所以不必检查特征,detectAdapter 函数会优先拾取你的自定义适配器。
autodialog 有一个单例的默认导出,你可以直接导入使用,也可以引入 Dialog 类,实现多例弹窗。
所谓大道至简,核心原理就只有这些内容了!
进阶使用
API
autodialog.show(content, options?)
|
选项
|
类型
|
默认值
|
说明
|
title
|
string
|
undefined
|
可选标题
|
props
|
object
|
{}
|
传递给组件的参数
|
showMask
|
boolean
|
true
|
是否显示遮罩层
|
allowScroll
|
boolean
|
false
|
是否允许滚动页面
|
animation
|
boolean
|
true
|
是否启用动画
|
animationDuration
|
number
|
200
|
动画持续时间(毫秒)
|
animationClass
|
{ enter?: string; leave?: string }
|
-
|
自定义动画类名
|
onBeforeOpen
|
() => void
|
-
|
打开前
|
onOpened
|
() => void
|
-
|
打开后
|
onBeforeClose
|
() => void
|
-
|
关闭前
|
onClosed
|
() => void
|
-
|
关闭后
|
onMaskClick
|
() => void
|
-
|
点击遮罩层时触发
|
自定义适配器(例如 Svelte)
import { Dialog } from 'autodialog.js'import { mount } from 'svelte'export const SvelteAdapter = { render(Component: any, { panel, props = {}, onClose }: any) { const instance = mount(Component, { target: panel, props: { ...props, onClose } }) ;(panel as any).__svelte__ = instance }, unmount(panel: HTMLElement) { const inst = (panel as any).__svelte__ inst?.destroy?.() delete (panel as any).__svelte__ }}// ✅ 注册自定义适配器(detect 可省略)Dialog.registerAdapter({ name: 'svelte', adapter: SvelteAdapter})
现在可以直接这样调用:
import MyDialog from './MyDialog.svelte'autodialog.show(MyDialog, { props: { text: '来自 Svelte 的弹窗 ✨' } })
设计理念
Autodialog 的设计遵循三个核心原则:
-
「框架独立」
:核心逻辑不依赖 Vue、React 或其他框架。
-
「可扩展性」
:任何渲染系统都可以通过 Adapter 接入。
-
「用户主导」
:样式、动画与生命周期完全开放给用户控制。
结语
希望 auto-plugin 的插件能给你带来帮助,让我们欢迎新成员:autodialog.js !
github:
Auto-Plugin/autodialog.js
npm:autodialog.js - npm
点
击
"
阅
读
原
文
"
了
解
详
情
~