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
194 lines
5.0 KiB
Vue
|
4 years ago
|
<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>
|