npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

stxdlg

v3.4.0

Published

仅支持vue3 稳定版本 A lightweight, fully customizable Vue 3 dialog manager with drag support

Readme

stxdlg - Vue 3 对话框管理器

npm version license

一个轻量级、高度可定制的 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 | - | 拖动结束回调 |

拖拽注意事项

  1. 必须设置定位:被拖动的元素需要 position: fixedposition: absolute
  2. 手柄元素:只有点击 handle 指定的元素才能触发拖动
  3. 关闭按钮排除:带有 .close-btn 类的元素会被排除,不会触发拖动
  4. 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 支持!