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

View File

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

View File

@ -2,14 +2,22 @@
<div v-transfer-dom :data-transfer="true"> <div v-transfer-dom :data-transfer="true">
<div :class="className"> <div :class="className">
<transition :name="transitions[0]"> <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>
<transition :name="transitions[1]"> <transition :name="transitions[1]">
<div v-if="shouldRenderInDom" v-show="value" class="micro-modal-content" :style="contentStyle"> <div v-if="shouldRenderInDom" v-show="value" class="micro-modal-content" :style="contentStyle">
<div class="micro-modal-close" @click="onClose"> <div class="micro-modal-tools" :class="{expanded: $A.isMainElectron}">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"> <div class="tool-fullscreen" @click="$emit('on-popout-window')">
<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 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">
</svg> <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> </div>
<ResizeLine <ResizeLine
class="micro-modal-resize" class="micro-modal-resize"
@ -146,11 +154,11 @@ export default {
} }
}, },
onClose() { onClose(isClick = false) {
if (!this.beforeClose) { if (!this.beforeClose) {
return this.handleClose(); return this.handleClose();
} }
const before = this.beforeClose(); const before = this.beforeClose(isClick);
if (before && before.then) { if (before && before.then) {
before.then(() => { before.then(() => {
this.handleClose(); this.handleClose();
@ -221,29 +229,66 @@ export default {
background-color: var(--modal-mask-bg, rgba(0, 0, 0, .4)); background-color: var(--modal-mask-bg, rgba(0, 0, 0, .4));
} }
&-close { &-tools {
position: absolute; position: absolute;
top: var(--status-bar-height, 0); top: var(--status-bar-height, 0);
left: -40px; left: -40px;
z-index: 1; z-index: 2;
width: 40px; min-width: 40px;
height: 40px; min-height: 40px;
border-radius: 50%;
display: var(--modal-close-display, flex); display: var(--modal-close-display, flex);
flex-direction: column;
align-items: center; align-items: center;
justify-content: center;
color: var(--modal-close-color, #ffffff);
cursor: pointer;
> svg { > div {
width: 24px; width: 40px;
height: 24px; height: 40px;
transition: transform 0.3s ease-in-out; 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 { &.expanded {
> svg { margin-top: -40px;
transform: rotate(-90deg); transition: margin-top 0.2s ease-in-out;
&:hover {
margin-top: 0;
}
> div {
&:hover {
> svg {
transform: scale(1.2);
}
}
&.tool-fullscreen {
display: flex;
}
} }
} }
} }