在 Vue3 项目中通过 iframe 嵌入外部页面,让 iframe 内部页面触发的弹窗能够突破 iframe 的边界,显示在 Vue3 主页面的层级上
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Vue3 iframe 弹窗外部显示示例(主页面)</title>
<script src="https://unpkg.com/vue@3.4.0/dist/vue.global.prod.js"></script>
<style>
body {
margin: 20px;
font-family: Arial, sans-serif;
}
.iframe-container {
position: relative;
width: 100%;
margin-bottom: 20px;
}
iframe {
border: 1px solid #ccc;
border-radius: 4px;
}
.global-popup {
position: fixed;
z-index: 9999;
padding: 20px;
background: #fff;
border: 1px solid #e5e7eb;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.popup-content {
margin-bottom: 16px;
}
button {
padding: 8px 16px;
cursor: pointer;
background: #409eff;
color: white;
border: none;
border-radius: 4px;
}
button:hover {
background: #66b1ff;
}
</style>
</head>
<body>
<h2>Vue3 主页面</h2>
<div id="app">
<div class="iframe-container">
<!-- 嵌入本地的iframe子页面 -->
<iframe
ref="iframeRef"
src="iframe-child.html"
width="100%"
height="400px"
frameborder="0"
></iframe>
</div>
<!-- 全局弹窗 -->
<teleport to="body">
<div
v-if="popupVisible"
class="global-popup"
:style="{ top: popupPosition.top + 'px', left: popupPosition.left + 'px' }"
>
<div class="popup-content" v-html="popupContent"></div>
<button @click="closePopup">关闭弹窗</button>
</div>
</teleport>
</div>
<script>
const { createApp, ref, onMounted, onUnmounted } = Vue;
createApp({
setup() {
// 弹窗相关状态
const iframeRef = ref(null);
const popupVisible = ref(false);
const popupContent = ref('');
const popupPosition = ref({ top: 100, left: 100 });
// 监听iframe发送的消息(本地预览取消origin校验)
const handleMessage = (e) => {
console.log('主页面接收消息:', e.data);
const { type, data } = e.data;
// 显示弹窗
if (type === 'showPopup') {
popupVisible.value = true;
popupContent.value = data.content;
popupPosition.value = {
top: data.top || 100,
left: data.left || 100
};
}
// 关闭弹窗
if (type === 'closePopup') {
popupVisible.value = false;
}
};
// 关闭弹窗
const closePopup = () => {
popupVisible.value = false;
// 通知iframe弹窗已关闭
if (iframeRef.value) {
iframeRef.value.contentWindow.postMessage(
{ type: 'popupClosed' },
'*' // 本地预览使用*
);
}
};
// 挂载/卸载监听
onMounted(() => {
window.addEventListener('message', handleMessage);
});
onUnmounted(() => {
window.removeEventListener('message', handleMessage);
});
return {
iframeRef,
popupVisible,
popupContent,
popupPosition,
closePopup
};
}
}).mount('#app');
</script>
</body>
</html>
2、iframe-child.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>iframe 子页面</title>
<style>
body {
margin: 20px;
font-family: Arial, sans-serif;
background-color: #f5f5f5;
}
.container {
max-width: 600px;
margin: 0 auto;
}
button {
margin: 10px 5px;
padding: 10px 20px;
cursor: pointer;
background: #67c23a;
color: white;
border: none;
border-radius: 4px;
font-size: 14px;
}
button:hover {
background: #85ce61;
}
.tips {
color: #666;
margin-top: 20px;
font-size: 14px;
}
</style>
</head>
<body>
<div class="container">
<h3>✨ iframe 内部页面</h3>
<p>点击下方按钮触发主页面弹窗:</p>
<button onclick="openPopupAtClick()">点击打开弹窗(点击位置)</button>
<button onclick="openCenterPopup()">打开居中弹窗</button>
<button onclick="closePopup()">关闭弹窗</button>
<div class="tips">
<p>💡 提示:</p>
<p>1. 弹窗会显示在主页面层级,突破iframe边界</p>
<p>2. 关闭弹窗后会通知iframe页面</p>
</div>
</div>
<script>
// 打开弹窗(点击位置)
function openPopupAtClick() {
// 获取点击位置
const clickX = window.event ? window.event.clientX : 200;
const clickY = window.event ? window.event.clientY : 200;
// 向父页面发送消息
window.parent.postMessage({
type: 'showPopup',
data: {
content: `
<h4>🎉 这是iframe触发的弹窗</h4>
<p>弹窗位置:点击按钮的位置</p>
<p>弹窗时间:${new Date().toLocaleTimeString()}</p>
<p>✅ 弹窗突破了iframe的边界显示在主页面</p>
`,
top: clickY,
left: clickX
}
}, '*'); // 本地预览使用*
}
// 打开居中弹窗
function openCenterPopup() {
// 计算主页面居中位置
const top = window.parent.innerHeight / 2 - 100;
const left = window.parent.innerWidth / 2 - 200;
window.parent.postMessage({
type: 'showPopup',
data: {
content: `
<h4>🎯 居中显示的弹窗</h4>
<p>这个弹窗显示在主页面正中间</p>
<p>即使iframe滚动,弹窗位置也不会变</p>
`,
top: top,
left: left
}
}, '*');
}
// 关闭弹窗
function closePopup() {
window.parent.postMessage({
type: 'closePopup'
}, '*');
}
// 监听主页面的回调
window.addEventListener('message', (e) => {
if (e.data.type === 'popupClosed') {
alert('✅ 主页面弹窗已关闭!');
}
});
</script>
</body>
</html>

浙公网安备 33010602011771号