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 支持:提供
useModalEnhancehook,灵活集成 - 📦 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/注意:发布前请确保:
- 已登录 npm:
npm login .npmrc配置正确- 版本号已更新
💡 注意事项
1. DOM 结构要求
- 组件默认依赖 Ant Design Vue 的 DOM 结构
- 如果自定义了 Modal DOM,需要通过
dragSelector指定拖拽头部选择器 useModalEnhance的modalRootRef需要指向包含.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 找不到模块或类型声明的错误,请检查以下几点:
确保已安装依赖:
npm install vue-ant-modal-enhance vue ant-design-vue检查 tsconfig.json 配置:
确保你的
tsconfig.json包含以下配置:{ "compilerOptions": { "moduleResolution": "bundler", // 或 "node" "types": ["vite/client"], "resolveJsonModule": true, "esModuleInterop": true, "skipLibCheck": true } }重启 TypeScript 服务器:
在 VS Code 中按
Ctrl+Shift+P(Mac:Cmd+Shift+P),输入 "TypeScript: Restart TS Server"检查 node_modules:
如果问题仍然存在,尝试删除
node_modules和package-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
