背景:
因为 vxe-table 模态弹窗 modal 默认没有最小化功能,且拖动窗口的时候,允许拖出屏幕边界的话,那么原来的界面可能就打不开,只能刷新系统了。所以只能修改源码来实现此功能,现在把代码公开出来给需要使用的人。(需要特别感谢我的同事何工,因为此功能主要是我同事何工实现的)
代码环境:Vue3
一、实现最终效果如图
最小化窗口
拖动窗口不允许拖出屏幕边界
最小化窗口可以进行层叠
二、代码实现过程如下
1、找到 node_modules\vxe-table\es\v-x-e-table\src\conf.js 文件,
定位到:dblclickZoom: true,
在其后增加代码: dblclickMinus: true, //新增最小化 2023-6-2
2、找到 node_modules\vxe-table\es\modal\src\modal.js 文件,
2.1 定位到:showZoom: Boolean,
在其后增加代码: showMinus: Boolean,//新增最小化 2023-6-2
2.2 定位到:
dblclickZoom: { type: Boolean, default: function () { return GlobalConfig.modal.dblclickZoom; } },
在其后增加代码: dblclickMinus: { type: Boolean, default: function () { return GlobalConfig.modal.dblclickMinus; } },//新增最小化 2023-6-2
2.3 定位到:zoomLocat: null,
在其后增加代码: isMinus: false,//新增最小化 2023-6-2
2.4 定位到:var revert = function
将方法代码改为:
var revert = function () {
return nextTick().then(function () {
var zoomLocat = reactData.zoomLocat;
if (zoomLocat) {
var boxElem = getBox();
reactData.zoomLocat = null;
Object.assign(boxElem.style, {
top: "".concat(zoomLocat.top, "px"),
left: "".concat(zoomLocat.left, "px"),
width: "".concat(zoomLocat.width, "px"),
height: "".concat(zoomLocat.height, "px")
});
reactData.isMinus = false;//新增最小化 2023-6-2
savePosStorage();
}
});
};
2.5.定位到:var toggleZoomEvent = function (evnt)
在该方法后添加新toggleMinusEvent方法,代码代码如下:
//新增最小化 2023-6-2
var toggleMinusEvent= function (evnt) {
return nextTick().then(function () {
var zoomLocat = reactData.zoomLocat;
var boxElem = getBox();
if (!zoomLocat) {
reactData.zoomLocat = {
top: boxElem.offsetTop,
left: boxElem.offsetLeft,
width: boxElem.offsetWidth + (boxElem.style.width ? 0 : 1),
height: boxElem.offsetHeight + (boxElem.style.height ? 0 : 1)
};
}
var left = 0;
var bottom = 0;
var isFind = true;
while (isFind){
left += 5;
bottom += 10;
var _a = allActivedModals[0].props.isMinus;
var _b = allActivedModals[0].reactData.visible;
var lastModal_1 = XEUtils.max(allActivedModals, function (item) { return item.reactData.modalZindex; });
var _props=JSON.parse(JSON.stringify(allActivedModals[0].props));
const el = allActivedModals.find(
(_vm) => _vm.reactData.visible == true
&& _vm.reactData.isMinus == true
&& parseInt(_vm.getBox().style.bottom) == bottom
&& parseInt(_vm.getBox().style.left) == left
&& _vm.getBox().style.top == 'auto'
);
if(el)
{
left = left + 5;
bottom = bottom + parseInt(el.getBox().style.height) -30;
isFind = true;
}else {
isFind = false;
}
}
Object.assign(boxElem.style, {
top: "auto",
bottom: "".concat(bottom, "px"),
left: "".concat(left, "px"),
width: "250px",
height: "43px",
overflow: "hidden"
});
reactData.isMinus = true;
savePosStorage();
});
};
2.6 定位到:var mousedownEvent = function (evnt)方法,
将该方法修改代码如下:
var mousedownEvent = function (evnt) {
var remember = props.remember, storage = props.storage;
var zoomLocat = reactData.zoomLocat;
var isMinus = reactData.isMinus;
var marginSize = XEUtils.toNumber(props.marginSize);
var boxElem = getBox();
if ((!zoomLocat || isMinus) && evnt.button === 0 && !getEventTargetNode(evnt, boxElem, 'trigger--btn').flag) {
evnt.preventDefault();
var domMousemove_1 = document.onmousemove;
var domMouseup_1 = document.onmouseup;
var disX_1 = evnt.clientX - boxElem.offsetLeft;
var disY_1 = evnt.clientY - boxElem.offsetTop;
var _a = getDomNode(), visibleHeight_1 = _a.visibleHeight, visibleWidth_1 = _a.visibleWidth;
document.onmousemove = function (evnt) {
evnt.preventDefault();
var offsetWidth = boxElem.offsetWidth;
var offsetHeight = boxElem.offsetHeight;
var minX = marginSize;
var maxX = visibleWidth_1 - offsetWidth - marginSize - 1;
maxX = Math.min( visibleWidth_1 - 42,maxX); //往最右边拖动。不能超过边界 2023-5-8
var minY = marginSize;
var maxY = visibleHeight_1 - offsetHeight - marginSize - 1;
maxY = Math.min((visibleHeight_1 - 42),maxY);//往下拖动。不能超过边界 2023-5-8
var left = evnt.clientX - disX_1;
var top = evnt.clientY - disY_1;
if (left > maxX) {
left = maxX;
}
if (left < minX) {
left = minX;
}
if (top > maxY) {
top = maxY;
}
if (top < minY) {
top = minY;
}
//自定义:拖动不能超过边界代码判断 --- 开始 hym 2023-5-8 ---
if (top < 0)
{
top = 0;//上面不能超出边界
}
if (left < 0)
{
left = 0;//最左边不能超出边界
}
//自定义:拖动不能超过边界代码判断 --- 结束 ---
boxElem.style.left = "".concat(left, "px");
boxElem.style.top = "".concat(top, "px");
boxElem.className = boxElem.className.replace(/\s?is--drag/, '') + ' is--drag';
};
document.onmouseup = function () {
document.onmousemove = domMousemove_1;
document.onmouseup = domMouseup_1;
if (remember && storage) {
nextTick(function () {
savePosStorage();
});
}
setTimeout(function () {
boxElem.className = boxElem.className.replace(/\s?is--drag/, '');
}, 50);
};
}
};
2.7.定位到:var renderTitles = function ()方法,
将该方法修改代码如下:
var renderTitles = function () {
var _a = props.slots, propSlots = _a === void 0 ? {} : _a, showClose = props.showClose, showZoom = props.showZoom,showMinus = props.showMinus, title = props.title;//新增最小化 2023-6-2
var zoomLocat = reactData.zoomLocat;
var titleSlot = slots.title || propSlots.title;
var cornerSlot = slots.corner || propSlots.corner;
var titVNs = [
h('div', {
class: 'vxe-modal--header-title'
}, titleSlot ? getSlotVNs(titleSlot({ $modal: $xemodal })) : (title ? getFuncText(title) : GlobalConfig.i18n('vxe.alert.title')))
];
var rightVNs = [];
if (cornerSlot) {
rightVNs.push(h('span', {
class: 'vxe-modal--corner-warpper'
}, getSlotVNs(cornerSlot({ $modal: $xemodal }))));
}
//新增最小化 2023-6-2
if (showMinus && !zoomLocat) {
rightVNs.push(h('i', {
class: ['vxe-modal--minus-btn', 'trigger--btn', 'vxe-icon--minus'],
title: '最小化',
onClick: toggleMinusEvent
}));
}
if (showZoom) {
rightVNs.push(h('i', {
class: ['vxe-modal--zoom-btn', 'trigger--btn', zoomLocat ? GlobalConfig.icon.MODAL_ZOOM_OUT : GlobalConfig.icon.MODAL_ZOOM_IN],
title: GlobalConfig.i18n("vxe.modal.zoom".concat(zoomLocat ? 'Out' : 'In')),
onClick: toggleZoomEvent
}));
}
if (showClose) {
rightVNs.push(h('i', {
class: ['vxe-modal--close-btn', 'trigger--btn', GlobalConfig.icon.MODAL_CLOSE],
title: GlobalConfig.i18n('vxe.modal.close'),
onClick: closeEvent
}));
}
titVNs.push(h('div', {
class: 'vxe-modal--header-right'
}, rightVNs));
return titVNs;
};
2.8 定位到:var renderHeaders = function ()方法,
将该方法修改代码如下:
var renderHeaders = function () {
var _a = props.slots, propSlots = _a === void 0 ? {} : _a, showZoom = props.showZoom, showMinus = props.showMinus, draggable = props.draggable;//新增最小化 2023-6-2
var isMsg = computeIsMsg.value;
var headerSlot = slots.header || propSlots.header;
var headVNs = [];
if (props.showHeader) {
var headerOns = {};
if (draggable) {
headerOns.onMousedown = mousedownEvent;
}
if (showZoom && props.dblclickZoom && props.type === 'modal') {
headerOns.onDblclick = toggleZoomEvent;
}
//新增最小化 2023-6-2
if (showMinus && props.dblclickMinus && props.type === 'modal') {
headerOns.onDblclick = toggleMinusEvent;
}
headVNs.push(h('div', __assign({ class: ['vxe-modal--header', {
'is--draggable': draggable,
'is--ellipsis': !isMsg && props.showTitleOverflow
}] }, headerOns), headerSlot ? (!reactData.inited || (props.destroyOnClose && !reactData.visible) ? [] : getSlotVNs(headerSlot({ $modal: $xemodal }))) : renderTitles()));
}
return headVNs;
};
三、使用方法
弹窗最小化使用方法 :添加属性 :show-minus="true"
例如
<template>
<vxe-modal
v-model="state.showDialog"
width="600"
height="170"
min-width="600"
min-height="150"
:remember="true"
:transfer="false"
:lockView="false"
:destroy-on-close="true"
:esc-closable="true"
show-zoom
:show-minus="true"
resize
:loading="state.loading"
:top="200"
:margin-size="-500"
show-footer
:mask="false"
>
<template #footer>
<el-button type="primary" @click="updateVisible(false)" size="default">关 闭</el-button>
</template>
<template #title>
<span style="color: red">录音播放 </span>
</template>
<template #default>
<div id="ScRx_Lybf">
<div style="margin-left: 1px; margin-right: 1px; margin-top: 1px; float: left; width: 100%">
<audio ref="scly_audio" style="width: 100%; outline: none" :src="Lyurl" controls="controls" autoplay="autoplay" @contextmenu.prevent />
</div>
</div>
</template>
</vxe-modal>
</template>