stxdlg
v3.4.0
Published
仅支持vue3 稳定版本 A lightweight, fully customizable Vue 3 dialog manager with drag support
Readme
stxdlg - Vue 3 对话框管理器
一个轻量级、高度可定制的 Vue 3 对话框管理器。
✨ 特性
- 🎨 样式完全自定义 - 不依赖任何 CSS,完全由你控制样式
- 📦 轻量级 - 核心代码简洁,无多余依赖
- 🚀 编程式 API - 使用
DialogManager.create()灵活管理对话框 - 🎯 TypeScript 支持 - 完整的类型定义
- 🖱️ 拖拽支持 - 内置
v-drag指令 - 🔄 响应式数据 - 支持动态更新对话框数据
- ⚡ 双格式支持 - ES Module + CommonJS
- 🛠️ 构建工具兼容 - 支持 Vite 和 Webpack
📦 安装
npm install stxdlg
# 或
yarn add stxdlg
# 或
pnpm add stxdlg🚀 快速开始
基础用法
<template>
<div>
<button @click="showDialog">打开对话框</button>
<!-- DialogContainer 是必需的容器组件 -->
<DialogContainer />
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { DialogManager } from 'stxdlg'
import MyDialog from './MyDialog.vue'
const showDialog = () => {
DialogManager.show('my-dialog')
}
onMounted(() => {
// 创建对话框
DialogManager.create(
'my-dialog',
MyDialog,
{ title: 'Hello', message: 'World' },
{
duration: 5000, // 5秒后自动关闭
closeCallback: () => console.log('对话框已关闭')
}
)
})
onUnmounted(() => {
DialogManager.destroy('my-dialog')
})
</script>全局注册(可选)
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import StxDialogPlugin from 'stxdlg'
const app = createApp(App)
// 安装插件(自动注册 DialogContainer 组件和 $dialogManager)
app.use(StxDialogPlugin)
app.mount('#app')🎨 样式自定义
完全自定义样式
stxdlg 不依赖任何预设样式,你可以完全自由地定义对话框外观:
<!-- MyDialog.vue -->
<template>
<div class="my-dialog">
<div class="dialog-header" v-drag>
{{ title }}
<button class="close-btn" @click="$emit('close')">×</button>
</div>
<div class="dialog-body">
{{ message }}
</div>
<div class="dialog-footer">
<button @click="$emit('confirm')">确定</button>
<button @click="$emit('cancel')">取消</button>
</div>
</div>
</template>
<script setup>
defineProps({
title: String,
message: String
})
defineEmits(['close', 'confirm', 'cancel'])
</script>
<style scoped>
.my-dialog {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
min-width: 400px;
background: white;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
z-index: 1000;
}
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid #eee;
cursor: move;
background: #f8f9fa;
border-radius: 8px 8px 0 0;
}
.dialog-body {
padding: 24px;
}
.dialog-footer {
padding: 16px;
text-align: right;
border-top: 1px solid #eee;
}
.close-btn {
background: transparent;
border: none;
font-size: 24px;
cursor: pointer;
}
</style>样式提示
- ✅ 你可以完全自由地定义样式
- ✅ 支持任何 CSS 框架(Tailwind CSS、Bootstrap、Element Plus 等)
- ✅ 支持 CSS Modules、Scoped CSS、CSS-in-JS
- ⚠️ DialogContainer 仅提供最小化的容器样式(
position: absolute) - ⚠️ 对话框组件需要自己定义样式
📖 API 文档
DialogManager
// 创建对话框
DialogManager.create(
name: string, // 对话框唯一标识
component: Component, // Vue 组件
props?: DialogData, // 传递给组件的 props
config?: DialogConfig // 配置选项
): DialogInstance
// 显示对话框
DialogManager.show(name: string): void
// 关闭对话框
DialogManager.close(name: string): void
// 设置数据
DialogManager.setData(name: string, data: DialogData): void
// 销毁对话框
DialogManager.destroy(name: string): void
// 获取实例
DialogManager.getInstance(name: string): DialogInstance | undefined
// 获取所有实例
DialogManager.getAllInstances(): Map<string, DialogInstance>DialogConfig
interface DialogConfig {
duration?: number // 自动关闭时间(毫秒)
closeCallback?: () => void // 关闭回调
container?: string | HTMLElement | Ref // 挂载容器
}DialogInstance
interface DialogInstance {
readonly $el: HTMLElement | null
readonly visible: boolean
readonly closed: boolean
show(): DialogInstance
hide(): DialogInstance
close(): void
updateData(data: DialogData): void
setData(data: DialogData): DialogInstance
destroy(): void
unmount(): void
}🖱️ 拖拽指令 v-drag
基础用法
<template>
<div class="dialog" v-drag>
<div class="dialog-header">拖动我</div>
<div class="dialog-body">内容区域</div>
</div>
</template>
<script setup>
import { vDrag } from 'stxdlg/directives'
</script>
<style scoped>
.dialog {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.dialog-header {
cursor: move;
}
</style>配置选项
<!-- 自定义拖动手柄 -->
<div v-drag="{ handle: '.my-header' }">
<!-- 启用窗口边界限制 -->
<div v-drag="{ handle: '.dialog-header', boundary: 'window' }">
<!-- 禁用边界限制 -->
<div v-drag="{ boundary: null }">
<!-- 禁用拖动 -->
<div v-drag="false">拖拽参数
| 参数 | 类型 | 默认值 | 说明 |
|-----|------|-------|------|
| handle | string | '.dialog-header' | 拖动手柄选择器 |
| enabled | boolean | true | 是否启用拖动 |
| boundary | 'window' \| 'parent' \| null | null | 边界限制 |
| onStart | (e: MouseEvent) => void | - | 拖动开始回调 |
| onMove | (e: MouseEvent, dx: number, dy: number) => void | - | 拖动过程回调 |
| onEnd | (e: MouseEvent) => void | - | 拖动结束回调 |
拖拽注意事项
- 必须设置定位:被拖动的元素需要
position: fixed或position: absolute - 手柄元素:只有点击
handle指定的元素才能触发拖动 - 关闭按钮排除:带有
.close-btn类的元素会被排除,不会触发拖动 - transform 兼容:首次拖动时会自动将
transform: translate(-50%, -50%)转换为实际位置
🔧 构建工具兼容性
Vite(推荐)
无需额外配置,开箱即用。
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()]
})Webpack(Vue CLI)
需要添加配置确保 Vue 单例:
// vue.config.js
const path = require('path')
module.exports = {
configureWebpack: {
resolve: {
symlinks: false, // ⚠️ 必需:确保 Vue 单例
alias: {
vue: path.resolve(__dirname, 'node_modules/vue')
}
}
}
}Webpack 重要说明:
- ⚠️ 必须设置
symlinks: false - ⚠️ 必须配置 Vue 别名
- 如果遇到对话框无法显示,请检查以上配置
📚 完整示例
<template>
<div>
<button @click="showBasicDialog">基础对话框</button>
<button @click="showDraggableDialog">可拖拽对话框</button>
<button @click="updateDialogData">更新数据</button>
<DialogContainer />
</div>
</template>
<script setup>
import { onMounted, onUnmounted } from 'vue'
import { DialogManager } from 'stxdlg'
import MyDialog from './MyDialog.vue'
const DIALOG_NAME = 'test-dialog'
// 创建对话框
onMounted(() => {
DialogManager.create(
DIALOG_NAME,
MyDialog,
{ title: '测试对话框', message: 'Hello World' },
{
closeCallback: () => {
console.log('对话框已关闭')
}
}
)
})
// 显示对话框
const showBasicDialog = () => {
DialogManager.show(DIALOG_NAME)
}
// 显示可拖拽对话框(需要在组件中添加 v-drag)
const showDraggableDialog = () => {
DialogManager.show(DIALOG_NAME)
}
// 更新对话框数据
const updateDialogData = () => {
DialogManager.setData(DIALOG_NAME, {
message: '数据已更新!'
})
}
// 清理
onUnmounted(() => {
DialogManager.destroy(DIALOG_NAME)
})
</script>🎯 最佳实践
1. 对话框命名
使用常量管理对话框名称:
const DIALOG_NAMES = {
EDIT_USER: 'edit-user',
DELETE_CONFIRM: 'delete-confirm',
SETTINGS: 'settings'
}
// 使用
DialogManager.create(DIALOG_NAMES.EDIT_USER, EditUserDialog, props)
DialogManager.show(DIALOG_NAMES.EDIT_USER)2. 组件设计
对话框组件应该发出标准事件:
<script setup>
defineEmits(['close', 'confirm', 'cancel'])
</script>DialogContainer 会自动处理这些事件。
3. 生命周期管理
在组件的 onUnmounted 中清理对话框:
onUnmounted(() => {
DialogManager.destroy('my-dialog')
})4. 容器指定
可以将对话框挂载到指定容器:
DialogManager.create(
'my-dialog',
MyComponent,
props,
{ container: '#modal-container' } // 或 ref
)🤝 兼容性
- Vue 3.x
- 现代浏览器(支持 ES6+)
- Node.js >= 16.0.0
📄 License
MIT © [Your Name]
🙏 致谢
如果你觉得这个插件有用,欢迎 Star 支持!
