• 作者:老汪软件技巧
  • 发表时间:2024-08-30 11:01
  • 浏览量:

iframe遵守同源策略,只有父页面与嵌套页面来自同一个域名,两者才能通信。所以首先需要进行同域代理。

1、怎么实现同域代理

server {
    listen 80;
    server_name yourdomain.com;
    location /proxy/ {
        proxy_pass http://targetdomain.com/;
        proxy_set_header Host targetdomain.com;
        add_header X-Frame-Options ALLOWALL;
    }
}

2、如何不改动子页面代码的情况下监听iframe嵌套页面的路由变化2.1、代理iframe的 History 对象(对跨域不适用)

async mounted() {
    this.watchIframeUrl();
  },
methods: {
  /**
 * 监听iframe的URL变化
 * 该方法通过劫持iframe窗口的历史记录API来实现
 * 主要用于捕获pushState和replaceState的操作
 */
watchIframeUrl() {
  // 获取iframe元素
  const iframe = this.$refs.iframe;
  // 获取iframe的窗口对象
  const iframeWindow = iframe.contentWindow;
  // 备份原始的pushState方法
  const originalPushState = iframeWindow.history.pushState;
  // 备份原始的replaceState方法
  const originalReplaceState = iframeWindow.history.replaceState;
  // 覆盖pushState方法,以监听URL的变化
  iframeWindow.history.pushState = function (...args) {
    // 调用原始的pushState方法,并传递所有参数
    originalPushState.apply(iframeWindow.history, args);
    // 打印pushState操作的参数和状态变化
    console.log('iframe pushState: ', args, args[2]);
    // 检查特定的URL,如果有匹配,则执行相关操作
    if (
      args[2] ===
      '/eolink/router/api/message/5247eb64-011d-055a-fe8f-741cfa8fe78d'
    ) {
      // 执行与特定URL相关的操作
      console.log('push');
    }
  };
  // 覆盖replaceState方法,以监听URL的变化
  iframeWindow.history.replaceState = function (...args) {
    // 调用原始的replaceState方法,并传递所有参数
    originalReplaceState.apply(iframeWindow.history, args);
    // 打印replaceState操作的参数和状态变化
    console.log('iframe replaceState: ', args, args[2]);
    // 检查特定的URL,如果有匹配,则执行相关操作
    if (args[2] === '/eolink/router/api/group/list') {
      // 执行与特定URL相关的操作
      console.log('replace');
    }
  };
}
}

但同样的,这种方法在跨域情况下是无法实现的。

2.2、通过 MutationObserver 观察 iframe 的 URL 变化

const iframe = document.querySelector('iframe');
const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.type === 'attributes' && mutation.attributeName === 'src') {
      console.log('iframe src changed to: ', iframe.src);
    }
  });
});
observer.observe(iframe, { attributes: true });

这种方法的局限性是:如果子页面是单页应用程序(SPA) ,它的 src 可能不会变,所以这个方法无法捕捉内部的路由变化。

_html监听属性变化_监听页面窗口尺寸变化的事件是

2.3、定时轮询 iframe 的 URL

data() {
    retuern {
        intervalId: null
    }
}
mounted() {
  const iframe = this.$refs.iframe;
    const pollingInterval = 1000; // 设置轮询间隔时间(毫秒)
    // 检查 iframe 的 URL
    const checkIframeUrl = () => {
      // 当前iframe的src
      const currentUrl = iframe.contentWindow.location.href;
      // 具体的逻辑
      const baseUrl = `${window.location.origin}/ang_kai-db`;
      if (
        ![
          `${baseUrl}/user-info`,
          `${baseUrl}/user-password`,
          `${baseUrl}/user-manage`
        ].includes(currentUrl)
      ) {
        this.setCss();
      }
    };
    // 启动轮询
    this.intervalId = setInterval(checkIframeUrl, pollingInterval);
}
destroyed() {
    this.cleanup();
  },
methods: {
  cleanup() {
      clearInterval(this.intervalId);
    },
}

这个方法虽然简单直接,但有一定的性能开销,而且如果 iframe 中的页面存在跨域限制(如 SameSite 属性),你将无法访问 contentWindow 的属性,这种方法就无法使用。

3、iframe扩展3.1、contents()获取iframe嵌套页面的dom树进行模拟点击

这个方法在我的一个需求中使用到了。需求是这样的:iframe嵌套了子页面,第一,需要将子页面的顶部菜单栏进行隐藏;第二,需要将子页面顶部菜单栏右上角的一些功能移到父页面的右上角,如下图所示:

当你需要操作 iframe 中的元素时,先使用 contents() 获取 iframe 内部的文档对象,然后在这个文档对象上使用 jQuery 方法来操作其内容。例如:

const iframeContent = $('#myIframe').contents();
const iframeElement = iframeContent.find('#childElement');
iframeContent.find('#childElement').click() // 模拟点击

这里的 contents() 用于获取 iframe 的文档对象,然后在该文档对象内使用 find() 查找特定的元素。