在 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>

  

posted @ 2026-03-03 21:37  迟到的时光  阅读(0)  评论(0)    收藏  举报