前言
朋友们好啊,我是 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.com/Auto-Plugin...
我取名可不是瞎取的(也瞎取过),这个 autodialog.js 是真正的框架无关的 dialog 组件。那么它的 auto 体现在哪呢?它可以自动识别传入的弹窗内容是来自什么框架!甚至不会破坏 vue 的响应式和 react 的状态,你甚至可以在 原生 html、svelte、solid、augular 中无缝使用,而不破坏框架本身的特性。更惊奇的是,调用方法是一模一样的。
在说实现思路之前,我想让你先感受一下 autodialog.js 的使用
快速使用示例
原生 HTML
ts
import autodialog from 'autodialog.js'
autodialog.show('<div>Hello World!</div>')
Vue 3
ts
import autodialog from 'autodialog.js'
import MyDialog from './MyDialog.vue'
autodialog.show(MyDialog, {
props: { title: '你好 Vue' })
React 18+
tsx
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 的,但是接受各种各样的适配器,我定义的适配器格式如下:
TypeScript
/**
* 适配器接口
* - render: 渲染内容到 panel 上
* - unmount: 卸载 panel 上的内容(可选)
*/
export interface Adapter {
render: (content: any, options: { container: HTMLElement; panel: HTMLElement;[key: string]: any }) => void
unmount?: (panel: HTMLElement) => void
}
比如要实现一个 vue 的适配器就是这样:
TypeScript
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 中,是这样自动判断内容来自什么组件,该用什么适配器的:
TypeScript
/**
* 自动检测逻辑(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)
ts
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
})
现在可以直接这样调用:
ts
import MyDialog from './MyDialog.svelte'
autodialog.show(MyDialog, { props: { text: '来自 Svelte 的弹窗 ✨' } })
设计理念
Autodialog 的设计遵循三个核心原则:
- 框架独立:核心逻辑不依赖 Vue、React 或其他框架。
- 可扩展性:任何渲染系统都可以通过 Adapter 接入。
- 用户主导:样式、动画与生命周期完全开放给用户控制。
结语
希望 auto-plugin 的插件能给你带来帮助,让我们欢迎新成员:autodialog.js !
github:github.com/Auto-Plugin...
npm:www.npmjs.com/package/aut...
别忘了免费的小星星点一点。