You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
5.0 KiB
Vue

<template>
<el-dialog
ref="dialogRef"
v-bind="getBindValue"
:fullscreen="fullscreen"
destroy-on-close
lock-scroll
:close-on-click-modal="false"
top="10vh"
>
<template #title>
<slot name="title">
{{ title }}
</slot>
<svg-icon
v-if="showFullscreen"
:icon-class="fullscreen ? 'exit-fullscreen' : 'fullscreen'"
class-name="dialog__icon"
@click="toggleFull"
/>
</template>
<!-- 弹窗内容 -->
<el-scrollbar
:class="
fullscreen && slots.footer
? 'com-dialog__content--footer'
: fullscreen && !slots.footer
? 'com-dialog__content--fullscreen'
: 'com-dialog__content'
"
>
<div class="content__wrap">
<slot></slot>
</div>
</el-scrollbar>
<template v-if="slots.footer" #footer>
<slot name="footer"></slot>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="Dialog">
import { ref, computed, PropType, nextTick, unref, useAttrs, useSlots } from 'vue'
import SvgIcon from '@/components/SvgIcon/index.vue'
const slots = useSlots()
const props = defineProps({
title: {
type: String as PropType<string>,
default: ''
},
// 是否显示全屏按钮
showFullscreen: {
type: Boolean as PropType<boolean>,
default: true
},
// 是否可以拖拽
draggable: {
type: Boolean as PropType<boolean>,
default: true
}
})
const dialogRef = ref<HTMLElement | null>(null)
const fullscreen = ref<boolean>(false)
const getBindValue = computed((): any => {
const delArr: string[] = ['showFullscreen', 'draggable']
const attrs = useAttrs()
const obj = { ...attrs, ...props }
for (const key in obj) {
if (delArr.indexOf(key) !== -1) {
delete obj[key]
}
}
return obj
})
function toggleFull(): void {
fullscreen.value = !fullscreen.value
// 全屏的时候需要重新定义left top
if (fullscreen.value && props.draggable) {
const dragDom = unref(dialogRef as any).$refs.dialogRef
dragDom.style.cssText += `;left:0px;top:0px;`
}
}
function initDraggable() {
nextTick(() => {
const dragDom = unref(dialogRef as any).$refs.dialogRef
const dialogHeaderEl = dragDom.querySelector('.el-dialog__header') as HTMLElement
dragDom.style.cssText += ';top:0px;'
dialogHeaderEl.style.cssText += ';cursor:move;user-select:none;'
dialogHeaderEl.onmousedown = (e) => {
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
const dragDomWidth = dragDom.offsetWidth
const dragDomHeight = dragDom.offsetHeight
const screenWidth = document.body.clientWidth
const screenHeight = document.body.clientHeight
const minDragDomLeft = dragDom.offsetLeft
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth
const minDragDomTop = dragDom.offsetTop
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight
const styleLeftStr = getComputedStyle(dragDom).left
const styleTopStr = getComputedStyle(dragDom).top
if (!styleLeftStr || !styleTopStr) return
let styleLeft: number
let styleTop: number
// Format may be "##%" or "##px"
if (styleLeftStr.includes('%')) {
styleLeft = +document.body.clientWidth * (+styleLeftStr.replace(/%/g, '') / 100)
styleTop = +document.body.clientHeight * (+styleTopStr.replace(/%/g, '') / 100)
} else {
styleLeft = +styleLeftStr.replace(/px/g, '')
styleTop = +styleTopStr.replace(/px/g, '')
}
document.onmousemove = (e) => {
let left = e.clientX - disX
let top = e.clientY - disY
// Handle edge cases
if (-left > minDragDomLeft) {
left = -minDragDomLeft
} else if (left > maxDragDomLeft) {
left = maxDragDomLeft
}
if (-top > minDragDomTop) {
top = -minDragDomTop
} else if (top > maxDragDomTop) {
top = maxDragDomTop
}
// Move current element
dragDom.style.cssText += `;left:${left + styleLeft}px;top:${top + styleTop}px;`
}
document.onmouseup = () => {
document.onmousemove = null
document.onmouseup = null
}
}
})
}
if (props.draggable) {
initDraggable()
}
</script>
<style lang="less" scoped>
.dialog__icon {
position: absolute;
top: 22px;
right: 45px;
font-size: 12px;
color: #909399;
cursor: pointer;
transition: color 0.2s;
&:hover {
color: #409eff;
}
}
.com-dialog__content {
.content__wrap {
padding-right: 10px;
}
:deep(.el-scrollbar__wrap) {
max-height: 600px; // 最大高度
overflow-x: hidden; // 隐藏横向滚动栏
}
}
.com-dialog__content--fullscreen {
:deep(.el-scrollbar__wrap) {
height: calc(~'100vh - 46px - 60px'); // 最大高度
}
}
.com-dialog__content--footer {
:deep(.el-scrollbar__wrap) {
max-height: calc(~'100vh - 46px - 60px - 70px'); // 最大高度
}
}
</style>