|
@@ -1,15 +1,31 @@
|
|
|
<template>
|
|
|
<div class="ui-drag-modal-box-hide" v-if="isBody">
|
|
|
- <Teleport to="#app">
|
|
|
- <div class="ui-drag-modal-box" :class="[isModalShow?'ui-drag-modal-show':'']" :id="'drag-modal-' + uuid"
|
|
|
- :style="{left: dragModalLeft + 'px', top: dragModalTop + 'px', width: widthVal + 'px', height: heightVal + 'px'}">
|
|
|
- <div class="ui-drag-modal-dialog shadow-xl" :class="[bg,ui]" :style="{width: widthVal + 'px', height: heightVal + 'px'}" @mousedown="dragModalMouseDown">
|
|
|
+ <Teleport to="#app" :disabled="!isBody">
|
|
|
+ <div class="ui-drag-modal-box"
|
|
|
+ :class="[isModalShow?'ui-drag-modal-show':'']"
|
|
|
+ :id="'drag-modal-' + uuid"
|
|
|
+ :style="{
|
|
|
+ left: dragModalLeft + 'px',
|
|
|
+ top: dragModalTop + 'px',
|
|
|
+ width: widthVal + 'px',
|
|
|
+ height: heightVal + 'px',
|
|
|
+ zIndex: isModalShow ? zIndex: -1
|
|
|
+ }"
|
|
|
+ @click.capture="dragModalCapture">
|
|
|
+ <div class="ui-drag-modal-dialog shadow-xl" :class="[bg,ui]"
|
|
|
+ :style="{width: widthVal + 'px', height: heightVal + 'px'}"
|
|
|
+ @mousedown="dragModalMouseDown">
|
|
|
<div class="ui-drag-modal-dialog-header" :class="titleBorder?'border-bottom':''">
|
|
|
<div class="ui-drag-modal-dialog-title text-lg" :class="titleUi">
|
|
|
<span v-if="title">{{title}}</span>
|
|
|
</div>
|
|
|
- <div class="ui-drag-modal-dialog-close" v-if="closeIcon" @click="_closeClick()">
|
|
|
- <HcIcon name="close"/>
|
|
|
+ <div class="ui-drag-modal-dialog-extra">
|
|
|
+ <div class="dialog-icon" @click="_fullscreenClick()">
|
|
|
+ <HcIcon :name="isFullscreen?'fullscreen-exit':'fullscreen'"/>
|
|
|
+ </div>
|
|
|
+ <div class="dialog-icon" v-if="closeIcon" @click="_closeClick()">
|
|
|
+ <HcIcon name="close"/>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="ui-drag-modal-dialog-body" @mousedown.stop="dragModalBodyMouseDown">
|
|
@@ -24,7 +40,9 @@
|
|
|
|
|
|
<script setup>
|
|
|
import { ref,nextTick,watch } from "vue"
|
|
|
-import { getRandom } from "vue-utils-plus"
|
|
|
+import {deepClone, getRandom} from "vue-utils-plus"
|
|
|
+import {useAppStore} from "~src/store";
|
|
|
+const useAppState = useAppStore()
|
|
|
//参数
|
|
|
const props = defineProps({
|
|
|
ui: {
|
|
@@ -53,7 +71,7 @@ const props = defineProps({
|
|
|
},
|
|
|
closeIcon: {
|
|
|
type: Boolean,
|
|
|
- default: false
|
|
|
+ default: true
|
|
|
},
|
|
|
isShow: {
|
|
|
type: Boolean,
|
|
@@ -67,30 +85,82 @@ const props = defineProps({
|
|
|
type: [Number,String],
|
|
|
default: 0
|
|
|
},
|
|
|
+ height: {
|
|
|
+ type: [Number,String],
|
|
|
+ default: 440
|
|
|
+ },
|
|
|
+ //是否排序置顶
|
|
|
+ isSortTop: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ eid: {
|
|
|
+ type: [Number,String],
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ //关闭时销毁
|
|
|
+ isCloseDestroy: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
})
|
|
|
|
|
|
//变量
|
|
|
-const uuid = getRandom()
|
|
|
const isBody = ref(false)
|
|
|
const isModalShow = ref(props.isShow)
|
|
|
+const uuid = props.eid || getRandom()
|
|
|
const dragModalLeft = ref(parseInt(props.lefts + ''))
|
|
|
const dragModalTop = ref(parseInt(props.tops + ''))
|
|
|
const widthVal = ref(parseInt(props.widths + ''))
|
|
|
-const heightVal = ref(440)
|
|
|
+const heightVal = ref(parseInt(props.height))
|
|
|
|
|
|
//监听
|
|
|
-watch(() => props.isShow, (isShow) => {
|
|
|
+watch(() => [
|
|
|
+ props.isShow
|
|
|
+], ([isShow]) => {
|
|
|
isModalShow.value = isShow;
|
|
|
})
|
|
|
|
|
|
-//
|
|
|
+//深度监听弹窗排序列表变化
|
|
|
+const dragModalSortTopList = ref(useAppState.dragModalSortTop)
|
|
|
+watch(() => [
|
|
|
+ useAppState.dragModalSortTop
|
|
|
+], ([sortTopList]) => {
|
|
|
+ dragModalSortTopList.value = sortTopList
|
|
|
+ setModalIndex(sortTopList)
|
|
|
+}, { deep: true })
|
|
|
+
|
|
|
+//设置窗口层级
|
|
|
+const zIndex = ref(8000)
|
|
|
+const setModalIndex = (sortTopList) => {
|
|
|
+ if (props.isSortTop) {
|
|
|
+ const index = sortTopList.indexOf(uuid)
|
|
|
+ zIndex.value = 8000 + (index + 1)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//页面渲染完成
|
|
|
nextTick(()=> {
|
|
|
//页面渲染完成后,再让 vue3 的 Teleport,把弹出框挂载到外部节点上。
|
|
|
isBody.value = true
|
|
|
+ if (props.isSortTop) {
|
|
|
+ const sortTopList = dragModalSortTopList.value
|
|
|
+ let index = sortTopList.indexOf(uuid)
|
|
|
+ if(index === -1) {
|
|
|
+ sortTopList.push(uuid)
|
|
|
+ index = sortTopList.length - 1
|
|
|
+ }
|
|
|
+ useAppState.setDragModalSortTop(sortTopList)
|
|
|
+ setModalIndex(sortTopList)
|
|
|
+ //窗口位置偏移,防止重叠在一起,误导用户
|
|
|
+ dragModalLeft.value = dragModalLeft.value + (index * 20)
|
|
|
+ dragModalTop.value = dragModalTop.value + (index * 20)
|
|
|
+ }
|
|
|
})
|
|
|
|
|
|
//弹窗拖动
|
|
|
const dragModalMouseDown = (event) => {
|
|
|
+ dragModalCapture()
|
|
|
// 阻止默认事件和冒泡
|
|
|
event.preventDefault()
|
|
|
event.stopPropagation()
|
|
@@ -123,11 +193,13 @@ const dragModalMouseDown = (event) => {
|
|
|
}
|
|
|
|
|
|
//禁止拖动
|
|
|
-const dragModalBodyMouseDown = () => {}
|
|
|
-
|
|
|
+const dragModalBodyMouseDown = () => {
|
|
|
+ dragModalCapture()
|
|
|
+}
|
|
|
|
|
|
//弹窗改变宽高
|
|
|
const dragModalResizeMouseDown = (event) => {
|
|
|
+ dragModalCapture()
|
|
|
// 阻止默认事件和冒泡
|
|
|
event.preventDefault()
|
|
|
event.stopPropagation()
|
|
@@ -156,7 +228,6 @@ const dragModalResizeMouseDown = (event) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
//事件
|
|
|
const emit = defineEmits(['close'])
|
|
|
const show = () => {
|
|
@@ -164,11 +235,81 @@ const show = () => {
|
|
|
}
|
|
|
const hide = () => {
|
|
|
isModalShow.value = false;
|
|
|
+ if (props.isCloseDestroy) {
|
|
|
+ destroyModal()
|
|
|
+ }
|
|
|
}
|
|
|
const _closeClick = () => {
|
|
|
+ emit('close', closeFunc)
|
|
|
+}
|
|
|
+//关闭弹窗
|
|
|
+const closeFunc = () => {
|
|
|
hide();
|
|
|
- emit('close', false)
|
|
|
}
|
|
|
+
|
|
|
+//缓存样式
|
|
|
+const cacheStyleJson = ref({})
|
|
|
+const isFullscreen = ref(false)
|
|
|
+
|
|
|
+//全屏
|
|
|
+const _fullscreenClick = () => {
|
|
|
+ if (isFullscreen.value) {
|
|
|
+ const styleJson = deepClone(cacheStyleJson.value)
|
|
|
+ dragModalLeft.value = styleJson.left
|
|
|
+ dragModalTop.value = styleJson.top
|
|
|
+ widthVal.value = styleJson.width
|
|
|
+ heightVal.value = styleJson.height
|
|
|
+ isFullscreen.value = false
|
|
|
+ } else {
|
|
|
+ const {clientWidth, clientHeight} = document.body
|
|
|
+ cacheStyleJson.value = deepClone({
|
|
|
+ width: widthVal.value,
|
|
|
+ height: heightVal.value,
|
|
|
+ left: dragModalLeft.value,
|
|
|
+ top: dragModalTop.value
|
|
|
+ })
|
|
|
+ dragModalLeft.value = 0
|
|
|
+ dragModalTop.value = 0
|
|
|
+ widthVal.value = clientWidth
|
|
|
+ heightVal.value = clientHeight
|
|
|
+ isFullscreen.value = true
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//弹窗被点击
|
|
|
+const dragModalCapture = () => {
|
|
|
+ if (props.isSortTop) {
|
|
|
+ const sortTopList = dragModalSortTopList.value
|
|
|
+ const index = sortTopList.indexOf(uuid)
|
|
|
+ if(index === -1) {
|
|
|
+ //检查是否已经存在,不存在则添加
|
|
|
+ sortTopList.push(uuid)
|
|
|
+ useAppState.setDragModalSortTop(sortTopList)
|
|
|
+ } else if(index !== sortTopList.length - 1) {
|
|
|
+ //检查是否在最上层,不在则置顶,可以解决多次点击时,频繁更改全局状态的问题
|
|
|
+ sortTopList.splice(index, 1)
|
|
|
+ sortTopList.push(uuid)
|
|
|
+ useAppState.setDragModalSortTop(sortTopList)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//销毁此弹窗
|
|
|
+const destroyModal = () => {
|
|
|
+ isBody.value = false;
|
|
|
+ if (props.isSortTop) {
|
|
|
+ const sortTopList = dragModalSortTopList.value
|
|
|
+ const index = sortTopList.indexOf(uuid)
|
|
|
+ if(index !== -1) {
|
|
|
+ sortTopList.splice(index, 1)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 暴露出去
|
|
|
+defineExpose({
|
|
|
+ destroyModal
|
|
|
+})
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|