perf: 优化应用弹窗

- 优化应用弹窗工具栏
- 优化应用弹窗全屏
This commit is contained in:
kuaifan 2025-07-26 10:45:31 +08:00
parent f7ed2ec3e3
commit 9969c3a7ac
3 changed files with 146 additions and 54 deletions

View File

@ -65,8 +65,10 @@ export default {
data() {
return {
src: this.url,
isReady: false,
isLoading: true,
hasMounted: false,
hearTbeatLastTime: 0,
}
},
@ -148,22 +150,31 @@ export default {
if (!this.isFromCurrentIframe(e)) {
return
}
const {type, message} = e.data;
const type = e.data.type;
const message = this.handleMessageEnsureJson(e.data.message);
switch (type) {
case 'MICRO_APP_READY':
this.handleMessageOfReady(this.handleMessageEnsureJson(message));
this.handleMessageOfReady(message);
break
case 'MICRO_APP_HEARTBEAT':
this.handleMessageOfHeartbeat(message);
break
case 'MICRO_APP_METHOD':
this.handleMessageOfMethod(this.handleMessageEnsureJson(message))
this.handleMessageOfMethod(message)
break
case 'MICRO_APP_FUNCTION_RESULT':
this.handleMessageOfFunctionResult(this.handleMessageEnsureJson(message))
this.handleMessageOfFunctionResult(message)
break
case 'MICRO_APP_BEFORE_CLOSE':
this.handleMessageOfBeforeClose(this.handleMessageEnsureJson(message))
this.handleMessageOfBeforeClose(message)
break
case 'MICRO_APP_BEFORE_UNLOAD':
this.handleMessageOfBeforeUnload(message);
break
default:
@ -179,29 +190,37 @@ export default {
// (MICRO_APP_READY)
handleMessageOfReady({supportBeforeClose}) {
this.handleLoad()
this.isReady = true
this.isLoading = false
if (!supportBeforeClose) {
return
}
this.$store.commit('microApps/update', {
name: this.name,
data: {
onBeforeClose: () => {
return new Promise(resolve => {
const message = {
id: $A.randomString(16),
name: this.name
if (supportBeforeClose) {
this.$store.commit('microApps/update', {
name: this.name,
data: {
onBeforeClose: () => {
if (this.hearTbeatLastTime && Date.now() - this.hearTbeatLastTime > 5000) {
return true //
}
this.$refs.iframe.contentWindow.postMessage({
type: 'MICRO_APP_BEFORE_CLOSE',
message
}, '*')
this.pendingBeforeCloses.set(message.id, resolve)
})
return new Promise(resolve => {
const message = {
id: $A.randomString(16),
name: this.name
}
this.$refs.iframe.contentWindow.postMessage({
type: 'MICRO_APP_BEFORE_CLOSE',
message
}, '*')
this.pendingBeforeCloses.set(message.id, resolve)
})
}
}
}
})
})
}
},
// (MICRO_APP_HEARTBEAT)
handleMessageOfHeartbeat() {
this.hearTbeatLastTime = Date.now()
},
// (MICRO_APP_METHOD)
@ -264,6 +283,18 @@ export default {
this.pendingBeforeCloses.delete(id)
},
// (MICRO_APP_BEFORE_UNLOAD)
handleMessageOfBeforeUnload() {
this.isReady = false
this.$store.commit('microApps/update', {
name: this.name,
data: {
onBeforeClose: () => true
}
})
},
// iframe
isFromCurrentIframe(event) {
try {

View File

@ -10,7 +10,8 @@
:transparent="app.transparent"
:autoDarkTheme="app.auto_dark_theme"
:keepAlive="app.keep_alive"
:beforeClose="async () => { await onBeforeClose(app.name) }">
:beforeClose="async (isClick) => { await onBeforeClose(app.name, isClick) }"
@on-popout-window="onPopoutWindow(app.name)">
<MicroIFrame
v-if="shouldRenderIFrame(app)"
:name="app.name"
@ -245,12 +246,7 @@ export default {
this.closeByName(name)
},
popoutWindow: async (windowConfig = null) => {
const app = this.microApps.find(item => item.name == name);
if (!app) {
$A.modalError("应用不存在");
return
}
await this.inlineBlank(app, windowConfig)
await this.onPopoutWindow(name, windowConfig)
},
openWindow: (params) => {
if (!$A.isJson(params)) {
@ -513,9 +509,10 @@ export default {
/**
* 关闭之前判断
* @param name
* @param {boolean} isClick 是否是点击关闭
* @returns {Promise<unknown>}
*/
onBeforeClose(name) {
onBeforeClose(name, isClick = false) {
return new Promise(resolve => {
const onClose = () => {
if ($A.isSubElectron) {
@ -527,6 +524,12 @@ export default {
const app = this.microApps.find(item => item.name == name);
if (!app) {
//
onClose()
return
}
if (isClick && app.keep_alive) {
// keep_alive onBeforeClose
onClose()
return
}
@ -569,6 +572,19 @@ export default {
})
},
/**
* 弹出窗口全屏
* @param name
*/
async onPopoutWindow(name, windowConfig = null) {
const app = this.microApps.find(item => item.name == name);
if (!app) {
$A.modalError("应用不存在");
return
}
await this.inlineBlank(app, windowConfig)
},
/**
* 是否渲染 iframe
* @param app

View File

@ -2,14 +2,22 @@
<div v-transfer-dom :data-transfer="true">
<div :class="className">
<transition :name="transitions[0]">
<div v-if="shouldRenderInDom" v-show="value" class="micro-modal-mask" @click="onClose" :style="maskStyle"></div>
<div v-if="shouldRenderInDom" v-show="value" class="micro-modal-mask" @click="onClose(false)" :style="maskStyle"></div>
</transition>
<transition :name="transitions[1]">
<div v-if="shouldRenderInDom" v-show="value" class="micro-modal-content" :style="contentStyle">
<div class="micro-modal-close" @click="onClose">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26">
<path d="M8.28596 6.51819C7.7978 6.03003 7.00634 6.03003 6.51819 6.51819C6.03003 7.00634 6.03003 7.7978 6.51819 8.28596L11.2322 13L6.51819 17.714C6.03003 18.2022 6.03003 18.9937 6.51819 19.4818C7.00634 19.97 7.7978 19.97 8.28596 19.4818L13 14.7678L17.714 19.4818C18.2022 19.97 18.9937 19.97 19.4818 19.4818C19.97 18.9937 19.97 18.2022 19.4818 17.714L14.7678 13L19.4818 8.28596C19.97 7.7978 19.97 7.00634 19.4818 6.51819C18.9937 6.03003 18.2022 6.03003 17.714 6.51819L13 11.2322L8.28596 6.51819Z" fill="currentColor"></path>
</svg>
<div class="micro-modal-tools" :class="{expanded: $A.isMainElectron}">
<div class="tool-fullscreen" @click="$emit('on-popout-window')">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 9V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v10c0 1.1.9 2 2 2h4"></path>
<rect width="10" height="7" x="12" y="13" rx="2"></rect>
</svg>
</div>
<div class="tool-close" @click="onClose(true)">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26">
<path d="M8.28596 6.51819C7.7978 6.03003 7.00634 6.03003 6.51819 6.51819C6.03003 7.00634 6.03003 7.7978 6.51819 8.28596L11.2322 13L6.51819 17.714C6.03003 18.2022 6.03003 18.9937 6.51819 19.4818C7.00634 19.97 7.7978 19.97 8.28596 19.4818L13 14.7678L17.714 19.4818C18.2022 19.97 18.9937 19.97 19.4818 19.4818C19.97 18.9937 19.97 18.2022 19.4818 17.714L14.7678 13L19.4818 8.28596C19.97 7.7978 19.97 7.00634 19.4818 6.51819C18.9937 6.03003 18.2022 6.03003 17.714 6.51819L13 11.2322L8.28596 6.51819Z" fill="currentColor"></path>
</svg>
</div>
</div>
<ResizeLine
class="micro-modal-resize"
@ -146,11 +154,11 @@ export default {
}
},
onClose() {
onClose(isClick = false) {
if (!this.beforeClose) {
return this.handleClose();
}
const before = this.beforeClose();
const before = this.beforeClose(isClick);
if (before && before.then) {
before.then(() => {
this.handleClose();
@ -221,29 +229,66 @@ export default {
background-color: var(--modal-mask-bg, rgba(0, 0, 0, .4));
}
&-close {
&-tools {
position: absolute;
top: var(--status-bar-height, 0);
left: -40px;
z-index: 1;
width: 40px;
height: 40px;
border-radius: 50%;
z-index: 2;
min-width: 40px;
min-height: 40px;
display: var(--modal-close-display, flex);
flex-direction: column;
align-items: center;
justify-content: center;
color: var(--modal-close-color, #ffffff);
cursor: pointer;
> svg {
width: 24px;
height: 24px;
transition: transform 0.3s ease-in-out;
> div {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
color: var(--modal-close-color, #ffffff);
cursor: pointer;
&:hover {
> svg {
transform: rotate(-90deg);
}
}
> svg {
width: 24px;
height: 24px;
transition: transform 0.2s ease-in-out;
}
&.tool-fullscreen {
display: none;
> svg {
width: 20px;
height: 20px;
}
}
}
&:hover {
> svg {
transform: rotate(-90deg);
&.expanded {
margin-top: -40px;
transition: margin-top 0.2s ease-in-out;
&:hover {
margin-top: 0;
}
> div {
&:hover {
> svg {
transform: scale(1.2);
}
}
&.tool-fullscreen {
display: flex;
}
}
}
}