使用的antdv组件库中的弹窗是没法拖动的,现在需求要使其标题栏可以在按住鼠标的时候弹窗可以自由拖动
components目录下建立两个文件
组件目录
- index.vue内容如下
<!--
* Description : 可拖拽antdv 弹窗的封装
* Date :2022-01-20 16:41:46
* LastEditors :Xuwei
* LastEditTime :2022-01-21 17:35:06
* FilePath :\WebGUI\src\components\DragModal\index.vue
-->
<template>
<a-modal
:class="[modalClass, simpleClass]"
:visible="visible"
v-bind="$props"
:footer="null"
:bodyStyle="{ padding: 0 }"
@ok="handleOk"
@cancel="handleCancel"
>
<div class="ant-modal-body" :style="bodyStyle">
<slot></slot>
</div>
<div class="ant-modal-footer relative">
<slot name="footer"></slot>
</div>
<div v-if="!title && title !== ''" slot="title">
<slot name="title"></slot>
</div>
</a-modal>
</template>
<script>
import props from './props.js'
var mouseDownX = 0
var mouseDownY = 0
var deltaX = 0
var deltaY = 0
var sumX = 0
var sumY = 0
var header = null // 标题头部
var contain = null
var modalContent = null
var onmousedown = false
export default {
name: 'DragModal',
mixins: [props],
props: {
// 容器的类名
modalClass: {
type: String,
default: () => {
return 'modal-box'
}
},
visible: {
type: Boolean,
default: () => {
return false
}
},
title: {
type: String,
default: () => {
return undefined
}
},
// width: {
// type: String,
// default: () => {
// return '70%'
// }
// },
footer: {
type: Boolean,
default: () => {
return true
}
}
},
data() {
return {}
},
computed: {
simpleClass() {
return Math.random()
.toString(36)
.substring(2)
}
},
watch: {
visible() {
this.$nextTick(() => {
this.initialEvent(this.visible)
})
}
},
mounted() {
this.$nextTick(() => {
this.initialEvent(this.visible)
})
},
created() {},
beforeDestroy() {
this.removeMove()
window.removeEventListener('mouseup', this.removeUp, false) // 移除鼠标按下需监听
},
methods: {
// 确定按钮回调
handleOk(e) {
this.resetNum()
this.$emit('ok', e)
},
// 取消按钮回调
handleCancel(e) {
this.resetNum()
this.$emit('cancel', e)
},
// 弹窗的初始位置初始化
resetNum() {
mouseDownX = 0
mouseDownY = 0
deltaX = 0
deltaY = 0
sumX = 0
sumY = 0
},
// 移动事件
handleMove(event) {
const delta1X = event.pageX - mouseDownX
const delta1Y = event.pageY - mouseDownY
deltaX = delta1X
deltaY = delta1Y
// console.log('delta1X:' + delta1X, 'sumX:' + sumX, 'delta1Y:' + delta1Y, 'sumY:' + sumY)
modalContent.style.transform = `translate(${delta1X + sumX}px, ${delta1Y +
sumY}px)`
},
// 弹窗初始化
initialEvent(visible) {
// console.log('--------- 初始化')
// console.log('simpleClass===>', this.simpleClass)
// console.log('document===>', document)
if (visible) {
setTimeout(() => {
window.removeEventListener('mouseup', this.removeUp, false)
contain = document.getElementsByClassName(this.simpleClass)[0]
header = contain.getElementsByClassName('ant-modal-header')[0]
modalContent = contain.getElementsByClassName('ant-modal-content')[0]
modalContent.style.left = 0
modalContent.style.transform = 'translate(0px,0px)'
// console.log('初始化-header:', header)
// console.log('初始化-contain:', contain)
// console.log('初始化-modalContent:', modalContent)
header.style.cursor = 'all-scroll'
// contain.onmousedown = (e) => {
header.onmousedown = e => {
onmousedown = true
mouseDownX = e.pageX
mouseDownY = e.pageY
document.body.onselectstart = () => false
window.addEventListener('mousemove', this.handleMove, false)
}
window.addEventListener('mouseup', this.removeUp, false)
}, 0)
}
},
// 鼠标停止
removeMove() {
window.removeEventListener('mousemove', this.handleMove, false)
},
// 鼠标抬起事件
removeUp(e) {
// console.log('removeUp')
document.body.onselectstart = () => true
if (onmousedown && !(e.pageX === mouseDownX && e.pageY === mouseDownY)) {
onmousedown = false
sumX = sumX + deltaX
sumY = sumY + deltaY
// console.log('sumX:' + sumX, 'sumY:' + sumY)
}
this.removeMove()
}
}
}
</script>
- props.js(就是antdv弹窗原生自带的所以参数,https://www.antdv.com/components/modal-cn/)
export default {
props: [
'afterClose', // Modal 完全关闭后的回调 function 无
'bodyStyle', // Modal body 样式 object {}
'cancelText', // 取消按钮文字 string| slot 取消
'centered', // 垂直居中展示 Modal Boolean false
'closable', // 是否显示右上角的关闭按钮 boolean true
'closeIcon', // 自定义关闭图标 VNode | slot - 1.5.0
'confirmLoading', // 确定按钮 loading boolean 无
'destroyOnClose', // 关闭时销毁 Modal 里的子元素 boolean false
// 'footer', // 底部内容,当不需要默认底部按钮时,可以设为 :footer="null" string|slot 确定取消按钮
'forceRender', // 强制渲染 Modal boolean false
'getContainer', // 指定 Modal 挂载的 HTML 节点 (instance): HTMLElement () => document.body
'keyboard', // 是否支持键盘 esc 关闭 boolean true
'mask', // 是否展示遮罩 Boolean true
'maskClosable', // 点击蒙层是否允许关闭 boolean true
'maskStyle', // 遮罩样式 object {}
'okText', // 确认按钮文字 string|slot 确定
'okType', // 确认按钮类型 string primary
'okButtonProps', // ok 按钮 props, 遵循 jsx规范 {props: ButtonProps, on: {}} -
'cancelButtonProps', // cancel 按钮 props, 遵循 jsx规范 {props: ButtonProps, on: {}} -
'title', // 标题 string|slot 无
'visible', // (v-model) 对话框是否可见 boolean 无
'width', // 宽度 string|number 520
'wrapClassName', // 对话框外层容器的类名 string -
'zIndex', // 设置 Modal 的 z-index Number 1000
'dialogStyle', // 可用于设置浮层的样式,调整浮层位置等 object - 1.6.1
'dialogClass' // 可用于设置浮层的类名 string
]
}
- main.js 当中引入
import DragModal from '@/components/DragModal'
Vue.component('DModal', DragModal)
4.调用使用
因为是在main.js当中全局引入了,所以,可以在vue模版文件中直接进行调用。需要注意的是弹窗底部footer确定和取消按钮部分,需要使用插槽重新定义,因为封装d-modal过程中使用的插槽对footer进行了定义
...
<!-- 删除任务确定对话框 -->
<d-modal
centered
class="modal-bk"
:title="$t('task.delete')"
:visible="delShow"
@cancel="cancelDel"
@ok="onOkDel"
:cancelText="$t('cancel')"
:okText="$t('confirm')"
>
<!-- 这里使用插槽重新自定footer的确定和取消按钮 -->
<template slot="footer">
<a-button @click="cancelDel">
{{ $t('cancel') }}
</a-button>
<a-button type="primary" @click="onOkDel" :loading="confirmLoading">
{{ $t('confirm') }}
</a-button>
</template>
<div class="modal-body">
<div class="modal-status">
<i class="am-icon am-icon-question" />
</div>
<div class="modal-content">
<a-radio-group v-model="valueDel">
<a-radio :value="0">
<!-- 只删除这个备份任务 -->
{{ $t('task.delete.current') }}
</a-radio>
<a-radio :value="1">
<!-- 永久删除这个备份任务和它的镜像文件。 -->
{{ $t('task.delete.current-forever') }}
</a-radio>
</a-radio-group>
</div>
</div>
</d-modal>
...
网友评论