mirror of https://gitee.com/xiaonuobase/snowy
【新增】实现iss对话框拖拽、缩放功能
parent
331cfe667b
commit
151914a015
|
@ -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>
|
|
@ -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
|
||||
]
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -59,7 +59,6 @@
|
|||
:closable="false"
|
||||
:footer="null"
|
||||
:width="600"
|
||||
style="overflow: hidden"
|
||||
destroyOnClose
|
||||
dialogClass="searchModal"
|
||||
:bodyStyle="{ maxHeight: '520px', overflow: 'auto', padding: '14px' }"
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue