惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
Y
Y Combinator Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
L
LangChain Blog
美团技术团队
N
Netflix TechBlog - Medium
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
B
Blog
博客园 - 司徒正美
爱范儿
爱范儿
D
DataBreaches.Net
月光博客
月光博客
U
Unit 42
B
Blog RSS Feed
Engineering at Meta
Engineering at Meta
Apple Machine Learning Research
Apple Machine Learning Research
Jina AI
Jina AI
MongoDB | Blog
MongoDB | Blog
腾讯CDC

蚊子的前端博客

微说 | 有的人觉得只要不考XX,一定能考好!-蚊子的前端博客 微说 | 春天来了-蚊子的前端博客 明天和意外不知道哪个先来-蚊子的前端博客 微说 | 既然错过了路口,就及时止损,重新规划路线上路-蚊子的前端博客 微说 | 2025年的出生人口数是792万-蚊子的前端博客 微说 | 工作年终总结,让写对接的接口的数量?-蚊子的前端博客 微说 | 温家宝:没有政治体制改革的成功 经济体制改革不可能进行到底-蚊子的前端博客 微说 | 违法犯罪了该不该被禁言?-蚊子的前端博客 微说 | 不明白为什么在推荐去俄罗斯旅游-蚊子的前端博客 微说 | 易中天论骗子-蚊子的前端博客 微说 | 一场大风吹散了秋天-蚊子的前端博客 微说 | 既要、又要、还要、更要!-蚊子的前端博客 又是一年的国庆雨季-蚊子的前端博客 微说 | 预估下2025年的出生人口数据-蚊子的前端博客 微说 | 可惜了我那些小时候的书本-蚊子的前端博客 微说 | 牛马有的是,驴不够了!-蚊子的前端博客 微说 | 能否有一条非户口也能高考的路-蚊子的前端博客 微说 | 小聊中医-蚊子的前端博客 微说 | 将要制作的一款新产品-蚊子的前端博客 微说 | 做人要有信-蚊子的前端博客 微说 | 好一个正义联盟-蚊子的前端博客 微说 | 都是见过吃过的主儿-蚊子的前端博客 微说 | 追求8小时工作制有错吗?-蚊子的前端博客 微说 | 如果尖锐的批评完全消失-蚊子的前端博客 微说 | 很好!-蚊子的前端博客 微说 | 封禁用户可以,但要告知具体原因-蚊子的前端博客 微说 | 面朝大海,春暖花开-蚊子的前端博客 微说 | 程序员的悲哀是什么?-蚊子的前端博客 微说 | 2025年出生人口的预测-蚊子的前端博客 前端在 LiveKit 中如何获取所有的参与者-蚊子的前端博客
Electron 中使用 webview 中打开外部链接跳转问题-蚊子的前端...
author · 2026-05-13 · via 蚊子的前端博客

最近遇到了一个比较棘手的问题,目前暂时还没有解决的方法,如果有同学曾经遇到过类似的问题,欢迎将解决方案分享出来。

我先简单描述一下问题:我目前使用的 Electron 版本是 34.x 版本,使用 webview 标签渲染外部链接。若该页面中使用了 window.open() 方法在新标签页中打开链接,在浏览器上是没有问题的,但在 electron 中是没有反应的。

1. 重写 window.open 方法 #

在咨询过 AI 后,是可以通过重写 window.open() 方法来实现的。有两种重写的方式,一种是在渲染层注入,另一种是在主进程注入。

渲染层注入:

webviewRef.current.addEventListener("dom-ready", () => {
  webviewRef.current.executeJavaScript(`
      // 强制覆盖,即使页面已经定义
      const originalOpen = window.open;
      window.open = function(url, name, features) {
          console.log('被拦截的 window.open:', url);
          // 主进程处理
          window.hivedoneApp.invoke("openUrl", { url });
          return null;
      };
      // 冻结这个属性,防止被再次修改
      Object.freeze(window.open);
  `);
});

主进程注入:

app.on("web-contents-created", (_, contents) => {
  contents
    .executeJavaScript(
      `
    // 保存原生 open
    // window._originalOpen = window.open; // 2

    // 永久重写
    window.open = function(url, target, features) {
      console.log('[重写] window.open:', url, Date.now());

      if (url && url.startsWith('http')) {
        // 主进程处理
        window.hivedoneApp.invoke("openUrl", { url });
      }

      // 阻止默认行为
      return null;
    };

    console.log('✅ 全局 window.open 重写成功!', Date.now());
  `,
    )
    .catch((err) => {});
});

这两种重写方式,都可以在 webview 中的页面生效。但若 webview 中加载的页面中还有一个 iframe,接着往下看。

2. webview 中嵌套 iframe 问题 #

但接下来就有两个问题一直没解决:

  1. 教程中都说 contents.setWindowOpenHandler() 可以拦截window.open()触发的行为,但实际测试发现,contents.setWindowOpenHandler() 并不能拦截 window.open() 触发的行为;目前还没找到原因;不过用重写 window.open() 方法倒也是可以解决。
  2. 若 webview 中加载页面中还有一个 iframe,iframe 中的 window.open() 是不会被重写的,若 iframe 中有 window.open() 触发的行为,直接就是无反应,同样的,iframe 中的 window.open() 方法也不会被 contents.setWindowOpenHandler() 拦截。

目前问题就卡住了,暂时还没有找到解决方法。

3. 更换成 WebContentView #

其实倒也是可以把 webview 替换成 WebContentView。但 WebContentView 是属于主进程创建的,层级太高,会遮挡住其他元素,导致其他元素无法正常显示。若页面中有一些弹窗、提示框等元素,就会有显示问题。

为了让这些弹窗能够正常显示,我可能还得要监控弹窗的显示和隐藏事件,然后再决定是隐藏还是显示 WebContentView。处理起来,也相当麻烦。我目前的方案是,监控页面元素的变动,然后判断网页中是否有弹窗、提示框等元素,若有,就隐藏 WebContentView,若无,就显示 WebContentView。

const observer = new MutationObserver(() => {
  const modals = Array.from(document.querySelectorAll(".ant-modal"));
  const popovers = Array.from(document.querySelectorAll(".ant-popover"));

  let isExisted =
    modals.filter((modal) => {
      return !modal.classList.contains("ant-modal-hidden") && !modal.classList.contains("ant-zoom-leave-active");
    }).length > 0;

  isExisted =
    isExisted ||
    popovers.filter((popover) => {
      return !popover.classList.contains("ant-popover-hidden");
    }).length > 0;

  // 若有弹窗、提示框等元素,就隐藏 WebContentView
  updateModalVisible(isExisted);
});
observer.observe(document.body, { childList: true, subtree: true, attributes: true });

4. 总结 #

用 webview 标签 和 WebContentView 两种方式都各有优劣,只能说更看重哪种交互方式,进行取舍。

当然,或许有什么更好的解决方案,欢迎分享出来。