【新增】实现iss对话框拖拽、缩放功能

pull/148/head
lingsoul 2023-07-31 15:45:52 +08:00 committed by 小诺
parent 331cfe667b
commit 151914a015
5 changed files with 283 additions and 8 deletions

View File

@ -0,0 +1,247 @@
<template>
<a-modal
:class="['my-modal', modalClass, simpleClass]"
:visible="visible"
v-bind="$props"
:width="modalWidth"
:footer="null"
:bodyStyle="{ padding: 0 }"
@ok="handleOk"
@cancel="handleCancel"
>
<div class="my-modal-body ant-modal-body" :style="bodyStyle">
<slot></slot>
</div>
<div class="ant-modal-footer relative" v-if="footer === true">
<slot name="footer">
<a-button @click="handleCancel"></a-button>
<a-button type="primary" @click="handleOk"></a-button>
</slot>
</div>
</a-modal>
</template>
<script>
import props from './props.js'
export default {
name: 'DragModal',
mixins: [props],
props: {
//
modalClass: {
type: String,
default: 'modal-box'
},
//
drag: {
type: Boolean,
default: true
},
//
resize: {
type: Boolean,
default: false
},
visible: {
type: Boolean,
default: false
},
title: {
type: String,
default: undefined
},
width: {
type: [Number, String],
default: '70%'
},
footer: {
type: Boolean,
default: true
}
},
data() {
return {
modalWidth: '',
contain: null,
//
header: null,
modalContent: null,
mouseDownX: 0,
mouseDownY: 0,
deltaX: 0,
deltaY: 0,
sumX: 0,
sumY: 0,
onmousedown: false,
//
modalBody: null,
myBody: null,
prevModalWidth: 0,
prevModalHeight: 0,
prevBodyWidth: 0,
prevBodyHeight: 0,
startX: 0,
startY: 0
}
},
computed: {
slotKeys() {
return Object.keys(this.$slots)
},
simpleClass() {
return Math.random().toString(36).substring(2)
}
},
watch: {
visible() {
this.$nextTick(() => {
this.initialEvent(this.visible)
})
}
},
mounted() {
this.$nextTick(() => {
this.initialEvent(this.visible)
})
},
created() {},
beforeUnmount() {
this.removeMove()
document.removeEventListener('mouseup', this.removeUp, false)
this.removeResize()
document.removeEventListener('mouseup', this.removeResize)
},
methods: {
changeWidth(width) {
this.modalWidth = width
},
handleOk(e) {
this.resetNum()
this.$emit('ok', e)
},
handleCancel(e) {
this.resetNum()
this.$emit('close', e)
},
resetNum() {
this.mouseDownX = 0
this.mouseDownY = 0
this.deltaX = 0
this.deltaY = 0
this.sumX = 0
this.sumY = 0
this.prevModalWidth = 0
this.prevModalHeight = 0
this.prevBodyWidth = 0
this.prevBodyHeight = 0
this.startX = 0
this.startY = 0
},
initialEvent(visible) {
// console.log('--------- ')
// console.log('simpleClass===>', this.simpleClass)
// console.log('document===>', document)
if (visible) {
this.resetNum()
//
document.removeEventListener('mouseup', this.removeUp, false)
this.contain = document.getElementsByClassName(this.simpleClass)[0]
// console.log('-contain:', this.contain)
this.changeWidth(this.$props.width)
if (this.$props.drag === true) {
this.header = this.contain.getElementsByClassName('ant-modal-header')[0]
this.modalContent = this.contain.getElementsByClassName('ant-modal-content')[0]
this.header.style.cursor = 'all-scroll'
this.modalContent.style.left = 0
this.modalContent.style.transform = 'translate(0px,0px)'
// console.log('-header:', this.header)
// console.log('-modalContent:', this.modalContent)
//
// this.contain.onmousedown = (event) => {
this.header.onmousedown = (event) => {
this.onmousedown = true
this.mouseDownX = event.pageX
this.mouseDownY = event.pageY
document.body.onselectstart = () => false
document.addEventListener('mousemove', this.handleMove, false)
}
document.addEventListener('mouseup', this.removeUp, false)
}
if (this.$props.resize === true) {
this.modalBody = this.contain.getElementsByClassName('ant-modal-body')[0]
this.myBody = this.contain.getElementsByClassName('my-modal-body')[0]
this.modalBody.style.overflow = 'hidden'
this.modalBody.style.resize = 'both'
this.myBody.style.overflow = 'auto'
this.myBody.style.height = 'auto'
// console.log('-modalBody:', this.modalBody)
// console.log('-myBody:', this.myBody)
//
this.modalBody.onmousedown = (event) => {
event.preventDefault()
const rect = this.modalBody.getBoundingClientRect()
const rightBorder = rect.x + rect.width - 17
const bottomBorder = rect.y + rect.height - 17
// console.log('rightBorder:' + rightBorder, 'clientX:' + event.clientX)
// console.log('bottomBorder:' + bottomBorder, 'clientY:' + event.clientY)
if (event.clientX >= rightBorder && event.clientY >= bottomBorder) {
this.prevModalWidth = this.modalBody.offsetWidth
this.prevModalHeight = this.modalBody.offsetHeight
this.prevBodyWidth = this.myBody.offsetWidth
this.prevBodyHeight = this.myBody.offsetHeight
this.startX = event.clientX
this.startY = event.clientY
document.addEventListener('mousemove', this.handleResize)
}
document.addEventListener('mouseup', this.removeResize)
}
}
}
},
handleMove(event) {
const delta1X = event.pageX - this.mouseDownX
const delta1Y = event.pageY - this.mouseDownY
this.deltaX = delta1X
this.deltaY = delta1Y
// console.log('delta1X:' + delta1X, 'sumX:' + this.sumX, 'delta1Y:' + delta1Y, 'sumY:' + this.sumY)
this.modalContent.style.transform = `translate(${delta1X + this.sumX}px, ${delta1Y + this.sumY}px)`
},
removeMove() {
document.removeEventListener('mousemove', this.handleMove, false)
},
removeUp(event) {
// console.log('removeUp')
document.body.onselectstart = () => true
if (this.onmousedown && !(event.pageX === this.mouseDownX && event.pageY === this.mouseDownY)) {
this.onmousedown = false
this.sumX = this.sumX + this.deltaX
this.sumY = this.sumY + this.deltaY
// console.log('sumX:' + this.sumX, 'sumY:' + this.sumY)
}
this.removeMove()
// this.checkMove()
},
handleResize(event) {
const diffX = event.clientX - this.startX
const diffY = event.clientY - this.startY
const minWidth = 180
const minHeight = 0
if (this.prevBodyWidth + diffX > minWidth) {
this.changeWidth(this.prevModalWidth + diffX + 'px')
// this.myBody.style.width = this.prevBodyWidth + diffX + 'px'
}
if (this.prevBodyHeight + diffY > minHeight) {
// this.modalBody.style.height = this.prevModalHeight + diffY + 'px'
this.myBody.style.height = this.prevBodyHeight + diffY + 'px'
}
},
removeResize() {
document.removeEventListener('mousemove', this.handleResize)
}
}
}
</script>

View File

@ -0,0 +1,30 @@
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
]
}

View File

@ -1,9 +1,9 @@
<template>
<a-modal v-if="isModal" :visible="visible" @cancel="cancel" v-bind="$attrs">
<drag-modal v-if="isModal" :visible="visible" v-bind="$attrs">
<template v-for="slotKey in slotKeys" #[slotKey]>
<slot :name="slotKey" />
</template>
</a-modal>
</drag-modal>
<a-drawer v-else :visible="visible" v-bind="$attrs" :footer-style="{ textAlign: 'right' }">
<template v-for="slotKey in slotKeys" #[slotKey]>
<slot :name="slotKey" />
@ -14,6 +14,7 @@
<script>
import { mapState } from 'pinia'
import { globalStore } from '@/store'
import DragModal from "@/components/DragModal/index.vue";
const FormContainerTypeEnum = {
DRAWER: 'drawer',
@ -21,6 +22,7 @@
}
export default {
name: 'XnFormContainer',
components: { DragModal },
inheritAttrs: false,
props: {
visible: {
@ -37,11 +39,6 @@
isModal() {
return FormContainerTypeEnum.MODAL === this.formStyle
}
},
methods: {
cancel() {
this.$emit('close')
}
}
}
</script>

View File

@ -59,7 +59,6 @@
:closable="false"
:footer="null"
:width="600"
style="overflow: hidden"
destroyOnClose
dialogClass="searchModal"
:bodyStyle="{ maxHeight: '520px', overflow: 'auto', padding: '14px' }"

View File

@ -9,6 +9,7 @@ import hljsCommon from 'highlight.js/lib/common'
import hljsVuePlugin from '@highlightjs/vue-plugin'
import STable from './components/Table/index.vue'
import Ellipsis from './components/Ellipsis/index.vue'
import DragModal from './components/DragModal/index.vue'
export default {
install(app) {
@ -20,6 +21,7 @@ export default {
// 注册常用组件
app.component('STable', STable)
app.component('Ellipsis', Ellipsis)
app.component('DragModal', DragModal)
// 统一注册antdv图标
for (const icon in antdvIcons) {