技术栈:
"dependencies": {
"vue": "^2.6.10",
"typescript": "^3.9.5",
"element-ui": "^2.13.2"
}
话不多说 直接上代码:
<template>
<el-dialog
ref="dialog"
v-dialogDrag="drag"
v-dialogEnlarge="{get: getVal, value: zoomable}"
v-bind="{ ...$props, ...$attrs }"
v-on="$listeners"
>
<template #title>
<slot name="title"></slot>
</template>
<template #default>
<slot name="default"></slot>
</template>
<template #footer>
<slot name="footer"></slot>
</template>
</el-dialog>
</template>
<script lang="ts">
import Clickoutside from 'element-ui/src/utils/clickoutside';
import Vue from 'vue';
import { Dialog } from 'element-ui';
import { Component, Prop, Emit, Model, Watch } from 'vue-property-decorator';
import '../directives/dialog-prop.js';
@Component({
components: {
ElDialog: Dialog,
},
props: {
...(Dialog as VueObject).props,
drag: {
type: Boolean,
default: false,
},
zoomable: {
type: Boolean,
default: false,
},
},
directives: { Clickoutside },
extends: Dialog,
})
export default class YhDialog extends Vue {
private getVal (val) {
this.$emit('resize', val); // 点击最大化时回调事件
}
}
</script>
拖拽/最大化使用自定义指令实现:(dialog-prop.js)
import Vue from 'vue';
/** 拖拽 */
Vue.directive('dialogDrag', {
bind(el, binding, vnode, oldVnode) {
if (!binding.value) {
return
}
const dialogHeaderEl = el.querySelector('.el-dialog__header');
const dragDom = el.querySelector('.el-dialog');
dialogHeaderEl.style.cssText += ';cursor:move;'
dragDom.style.cssText += ';top:0px;'
drag(dialogHeaderEl, dragDom)
}
})
/** 最大化(支持拖拽) */
Vue.directive('dialogEnlarge', {
bind(el, binding, vnode, oldVnode) {
const attrs = vnode.data.attrs
if (!binding.value.value) {
return
}
let resizeEvent = new CustomEvent('drag-resize', {
detail: '尺寸变化',
bubbles: false
});
//初始化不最大化
el.fullscreen = false;
//弹框可拉伸最小宽高
let minWidth = 400;
let minHeight = 300;
//当前宽高
let nowWidth = minWidth;
let nowHight = minHeight;
//当前顶部高度
let nowMarginTop = 0;
//获取弹框头部(这部分可双击全屏)
const dialogHeaderEl = el.querySelector('.el-dialog__header');
//弹窗
const dragDom = el.querySelector('.el-dialog');
dragDom.className += ' el-drag-dialog';
//清除选择头部文字效果
dialogHeaderEl.onselectstart = new Function("return false");
//头部加上可拖动cursor
if (attrs.drag) {
dialogHeaderEl.style.cursor = 'move';
dialogHeaderEl.style.cssText += ';cursor:move;'
dragDom.style.cssText += ';top:0px;'
drag(dialogHeaderEl, dragDom)
}
//头部插入最大化最小化元素
let maxMin = document.createElement("button");
maxMin.className += ' el-dialog__headerbtn el-dialog__minmax';
maxMin.style.right = '40px';
maxMin.style.color = '#fff';
maxMin.title = el.fullscreen ? '还原' : '最大化';
maxMin.innerHTML = '<i class=' + (el.fullscreen ? '"el-icon-crop"' : '"el-icon-full-screen"') + ' onMouseOver="this.style.color=\'#909399\'" onMouseOut="this.style.color=\'#fff\'"></i>';
dialogHeaderEl.insertBefore(maxMin, dialogHeaderEl.childNodes[1]);
let bodyHeight = 'auto';
function setMaxMin() {
if (el.fullscreen) {
let i = maxMin.querySelector('.el-icon-crop');
i.classList.remove('el-icon-crop');
i.classList.add('el-icon-full-screen');
maxMin.innerHTML = '<i class="el-icon-full-screen"></i>';
maxMin.title = '最大化';
dragDom.style.height = "auto";
dragDom.style.width = nowWidth + 'px';
dragDom.style.margin = '10vh auto 50px';
el.fullscreen = false;
if (attrs.drag) {
dialogHeaderEl.style.cursor = 'move';
dialogHeaderEl.style.cssText += ';cursor:move;'
dragDom.style.cssText += ';top:0px;'
drag(dialogHeaderEl, dragDom)
}
dragDom.querySelector('.el-dialog__body').style.height = bodyHeight;
dragDom.querySelector('.el-dialog__body').style['max-height'] = '55vh';
} else {
let i = maxMin.querySelector('.el-icon-full-screen');
i.classList.remove('el-icon-full-screen');
i.classList.add('el-icon-crop');
maxMin.title = '还原';
bodyHeight = dragDom.querySelector('.el-dialog__body').offsetHeight + 'px';
nowHight = dragDom.clientHeight;
nowWidth = dragDom.clientWidth;
nowMarginTop = dragDom.style.marginTop;
dragDom.style.left = 0;
dragDom.style.top = 0;
dragDom.style.height = "100%";
dragDom.style.width = "100%";
dragDom.style.margin = 0;
dragDom.querySelector('.el-dialog__body').style.height = '100vh';
dragDom.querySelector('.el-dialog__body').style['max-height'] = 'none';
el.fullscreen = true;
dialogHeaderEl.style.cursor = 'initial';
dialogHeaderEl.onmousedown = null;
}
el.dispatchEvent(resizeEvent);
binding.value.get(el.fullscreen)
}
//点击放大缩小效果
maxMin.onclick = setMaxMin;
//双击头部效果
dialogHeaderEl.ondblclick = setMaxMin;
}
})
/** 拖拽方法 */
function drag(el, dragDom) {
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = (function () {
if (window.document.currentStyle) {
return (dom, attr) => dom.currentStyle[attr];
} else {
return (dom, attr) => getComputedStyle(dom, false)[attr];
}
})()
el.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - el.offsetLeft;
const disY = e.clientY - el.offsetTop;
const screenWidth = document.body.clientWidth; // body当前宽度
const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取)
const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
const dragDomheight = dragDom.offsetHeight; // 对话框高度
const minDragDomLeft = dragDom.offsetLeft;
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;
const minDragDomTop = dragDom.offsetTop;
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;
// 获取到的值带px 正则匹配替换
let styL = sty(dragDom, 'left');
let styT = sty(dragDom, 'top');
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (styL.includes('%')) {
styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100);
styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100);
} else {
styL = +styL.replace(/\px/g, '');
styT = +styT.replace(/\px/g, '');
};
document.onmousemove = function (e) {
// 通过事件委托,计算移动的距离
let left = e.clientX - disX;
let top = e.clientY - disY;
// 边界处理
if (-(left) > minDragDomLeft) {
left = -(minDragDomLeft);
} else if (left > maxDragDomLeft) {
left = maxDragDomLeft;
}
if (-(top) > minDragDomTop) {
top = -(minDragDomTop);
} else if (top > maxDragDomTop) {
top = maxDragDomTop;
}
// 移动当前元素
dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
};
document.onmouseup = function (e) {
document.onmousemove = null;
document.onmouseup = null;
};
}
}
最大化样式:
拖拽样式:
代码使用:
<template>
<xx-dialog
:drag="true" //支持拖拽
:zoomable="true" //支持放大
>
</xx-dialog>
</template>