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 🙏

© 2025 – Pkg Stats / Ryan Hefner

vue-ant-modal-enhance

v1.2.2

Published

A Vue 3 hook for modal scroll height and draggable modal, compatible with Ant Design Vue.

Downloads

392

Readme

vue-ant-modal-enhance

Vue 3 模态框增强工具库:自动计算内容最大高度、支持拖拽(鼠标 + 触摸)、边界检测、吸附效果,兼容 Ant Design Vue。


✨ 特性

  • 🎯 自动高度计算:根据视口自动计算 modal 内容最大高度
  • 🖱️ 拖拽支持:支持鼠标和触摸拖拽,兼容移动端
  • 📐 边界检测:拖拽时自动检测边界,防止 modal 移出视口
  • 🧲 吸附效果:支持拖拽到边缘时自动吸附(可配置方向)
  • 🎨 组件封装:提供 <EnhancedModal /> 组件,开箱即用
  • 🔧 Hook 支持:提供 useModalEnhance hook,灵活集成
  • 📦 TypeScript:完整的 TypeScript 类型支持

📦 安装

npm install vue-ant-modal-enhance
# 或
yarn add vue-ant-modal-enhance
# 或
pnpm add vue-ant-modal-enhance

注意:本库需要配合 Ant Design Vue 使用,请确保项目中已安装 ant-design-vue


🚀 快速开始

方式一:使用组件(推荐)

最简单的方式,直接使用封装好的 <EnhancedModal /> 组件:

<template>
  <EnhancedModal
    v-model:visible="visible"
    title="示例弹框"
    :enableDrag="true"
    :scrollOffset="180"
  >
    <div v-for="i in 100" :key="i">内容行 {{ i }}</div>
  </EnhancedModal>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { EnhancedModal } from 'vue-ant-modal-enhance'

const visible = ref(false)
</script>

方式二:使用 Hook

如果你需要更灵活的控制,可以使用 useModalEnhance hook:

<template>
  <a-modal
    v-model:visible="visible"
    title="示例弹框"
    @afterOpen="initDrag"
  >
    <div
      ref="rootRef"
      :style="{ maxHeight: scrollHeight + 'px', overflowY: 'auto' }"
    >
      <div v-for="i in 100" :key="i">内容行 {{ i }}</div>
    </div>
  </a-modal>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useModalEnhance } from 'vue-ant-modal-enhance'

const visible = ref(false)
const rootRef = ref<HTMLElement | null>(null)

const { scrollHeight, initDrag } = useModalEnhance(rootRef, {
  scrollOffset: 180,
  enableDrag: true,
  dragSelector: '.ant-modal-header',
  snapThreshold: 24,
  snapTo: ['left', 'right', 'top']
})
</script>

📖 使用指南

1. EnhancedModal 组件

<EnhancedModal /> 是对 Ant Design Vue <a-modal> 的增强封装,内置了滚动高度计算和拖拽功能。

Props

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | visible | boolean | false | 是否显示(支持 v-model:visible) | | title | string | '' | 标题 | | width | number \| string | 800 | 宽度 | | maskClosable | boolean | false | 点击遮罩是否关闭 | | destroyOnClose | boolean | true | 关闭时销毁内容 | | enableDrag | boolean | true | 是否启用拖拽 | | scrollOffset | number | 160 | 滚动高度计算的偏移量(px) | | dragSelector | string | '.ant-modal-header' | 拖拽触发元素的选择器 | | snapThreshold | number | 24 | 吸附阈值(px) | | snapTo | ('left'\|'right'\|'top'\|'bottom'\|'none')[] | ['left','right','top'] | 吸附方向 | | getContainer | string \| Function | undefined | 指定 Modal 挂载的 DOM 节点 |

Events

| 事件名 | 参数 | 说明 | |--------|------|------| | update:visible | (visible: boolean) | 显示状态变化 | | ok | () | 点击确定按钮 | | cancel | () | 点击取消按钮或关闭 |

Slots

| 插槽名 | 说明 | |--------|------| | default | 弹框内容 | | footer | 自定义底部按钮(不提供时使用默认的"取消/确定"按钮) |

使用示例

<template>
  <!-- 基础用法 -->
  <EnhancedModal
    v-model:visible="visible1"
    title="基础弹框"
  >
    <div>内容...</div>
  </EnhancedModal>

  <!-- 自定义 footer -->
  <EnhancedModal
    v-model:visible="visible2"
    title="自定义底部"
  >
    <div>内容...</div>
    <template #footer>
      <a-button @click="visible2 = false">关闭</a-button>
      <a-button type="primary" @click="handleOk">提交</a-button>
    </template>
  </EnhancedModal>

  <!-- 禁用拖拽 -->
  <EnhancedModal
    v-model:visible="visible3"
    title="禁用拖拽"
    :enableDrag="false"
  >
    <div>内容...</div>
  </EnhancedModal>

  <!-- 自定义吸附方向 -->
  <EnhancedModal
    v-model:visible="visible4"
    title="仅左右吸附"
    :snapTo="['left', 'right']"
  >
    <div>内容...</div>
  </EnhancedModal>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { EnhancedModal } from 'vue-ant-modal-enhance'

const visible1 = ref(false)
const visible2 = ref(false)
const visible3 = ref(false)
const visible4 = ref(false)

const handleOk = () => {
  console.log('提交')
  visible2.value = false
}
</script>

2. useModalEnhance Hook

useModalEnhance 是一个组合式函数,提供更灵活的集成方式。

函数签名

function useModalEnhance(
  modalRootRef: Ref<HTMLElement | null>,
  options?: ModalEnhanceOptions
): {
  scrollHeight: Ref<number>
  initDrag: () => void
  destroyDrag: () => void
  isDragging: Ref<boolean>
}

参数说明

modalRootRef
类型:Ref<HTMLElement | null>
说明:modal 根元素的 ref,需要指向包含 .ant-modal 的元素。

options
类型:ModalEnhanceOptions

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | scrollOffset | number | 160 | 滚动高度计算的偏移量(px) | | enableDrag | boolean | true | 是否启用拖拽 | | dragSelector | string | '.ant-modal-header' | 拖拽触发元素的选择器 | | snapThreshold | number | 24 | 吸附阈值(px),距离边缘多少像素时触发吸附 | | snapTo | ('left'\|'right'\|'top'\|'bottom'\|'none')[] | ['left','right','top'] | 吸附方向数组 |

返回值

| 属性 | 类型 | 说明 | |------|------|------| | scrollHeight | Ref<number> | 计算后的最大内容高度(px) | | initDrag | () => void | 初始化拖拽功能,需要在 modal 打开后调用 | | destroyDrag | () => void | 销毁拖拽功能 | | isDragging | Ref<boolean> | 当前是否正在拖拽 |

Hook 使用示例

<template>
  <a-modal
    v-model:visible="visible"
    title="Hook 示例"
    @afterOpen="initDrag"
    @afterClose="destroyDrag"
  >
    <div
      ref="rootRef"
      :style="{
        maxHeight: scrollHeight + 'px',
        overflowY: 'auto',
        paddingRight: '12px'
      }"
    >
      <div v-for="i in 100" :key="i">内容行 {{ i }}</div>
    </div>
  </a-modal>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useModalEnhance } from 'vue-ant-modal-enhance'

const visible = ref(false)
const rootRef = ref<HTMLElement | null>(null)

const { scrollHeight, initDrag, destroyDrag, isDragging } = useModalEnhance(
  rootRef,
  {
    scrollOffset: 180,
    enableDrag: true,
    dragSelector: '.ant-modal-header',
    snapThreshold: 24,
    snapTo: ['left', 'right', 'top']
  }
)

// 监听拖拽状态
watch(isDragging, (dragging) => {
  console.log('拖拽状态:', dragging)
})
</script>

3. vDraggable 指令(备用方案)

如果上述方式都不适合,可以使用指令方式:

// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { vDraggable } from 'vue-ant-modal-enhance'

const app = createApp(App)
app.directive('draggable', vDraggable)
app.mount('#app')
<template>
  <div v-draggable="{ dragSelector: '.ant-modal-header' }">
    <a-modal v-model:visible="visible" title="指令示例">
      <div>内容...</div>
    </a-modal>
  </div>
</template>

🔧 构建和发布

本地开发

# 安装依赖
npm install

# 构建
npm run build

发布到 npm

# 发布(会自动更新版本号、生成 CHANGELOG、构建并发布)
npm run release

# 或手动发布
npm publish --access public --registry=https://registry.npmjs.org/

注意:发布前请确保:

  1. 已登录 npm:npm login
  2. .npmrc 配置正确
  3. 版本号已更新

💡 注意事项

1. DOM 结构要求

  • 组件默认依赖 Ant Design Vue 的 DOM 结构
  • 如果自定义了 Modal DOM,需要通过 dragSelector 指定拖拽头部选择器
  • useModalEnhancemodalRootRef 需要指向包含 .ant-modal 的元素

2. 吸附效果配置

  • 若想禁用吸附效果,将 snapTo 设为空数组 []
  • 支持的方向:'left''right''top''bottom'
  • snapThreshold 控制距离边缘多少像素时触发吸附

3. 初始位置

  • 若想让 modal 初始位置居中,请确保 a-modal 在打开时没有 left/top 样式
  • Hook 会自动设置初始 left/top 居中

4. 移动端兼容

  • 已做触摸事件兼容,支持移动端拖拽
  • 注意 a-modal 本身在某些平台可能会改变 DOM 或监听 touch 事件
  • 如遇冲突,可将 getContainer 指向 body

5. Footer 插槽

  • <EnhancedModal />footer 插槽需要直接写在组件标签下(如 <template #footer>
  • 组件内部自带"取消/确定"默认按钮,可按需覆盖

6. 性能优化

  • 拖拽过程中会自动添加过渡动画,提升用户体验
  • 建议在 modal 关闭时调用 destroyDrag() 清理事件监听

7. TypeScript 类型支持

如果遇到 TypeScript 找不到模块或类型声明的错误,请检查以下几点:

  1. 确保已安装依赖

    npm install vue-ant-modal-enhance vue ant-design-vue
  2. 检查 tsconfig.json 配置

    确保你的 tsconfig.json 包含以下配置:

    {
      "compilerOptions": {
        "moduleResolution": "bundler", // 或 "node"
        "types": ["vite/client"],
        "resolveJsonModule": true,
        "esModuleInterop": true,
        "skipLibCheck": true
      }
    }
  3. 重启 TypeScript 服务器

    在 VS Code 中按 Ctrl+Shift+P(Mac: Cmd+Shift+P),输入 "TypeScript: Restart TS Server"

  4. 检查 node_modules

    如果问题仍然存在,尝试删除 node_modulespackage-lock.json,然后重新安装:

    rm -rf node_modules package-lock.json
    npm install

📝 完整示例

<template>
  <div>
    <a-button @click="visible = true">打开弹框</a-button>

    <EnhancedModal
      v-model:visible="visible"
      title="完整示例"
      :width="900"
      :enableDrag="true"
      :scrollOffset="180"
      :snapThreshold="24"
      :snapTo="['left', 'right', 'top']"
      @ok="handleOk"
      @cancel="handleCancel"
    >
      <div>
        <h3>这是一个增强的 Modal</h3>
        <p>支持自动计算高度、拖拽、边界检测和吸附效果</p>
        <div v-for="i in 100" :key="i" style="padding: 8px 0; border-bottom: 1px solid #eee">
          内容行 {{ i }}
        </div>
      </div>
    </EnhancedModal>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { EnhancedModal } from 'vue-ant-modal-enhance'

const visible = ref(false)

const handleOk = () => {
  console.log('确定')
  visible.value = false
}

const handleCancel = () => {
  console.log('取消')
  visible.value = false
}
</script>

📄 License

MIT


🔗 相关链接