为啥 onload 事件在使用 window.open 打开的选项卡上不起作用?

Posted

技术标签:

【中文标题】为啥 onload 事件在使用 window.open 打开的选项卡上不起作用?【英文标题】:Why doesn't onload event work on a tab opend with window.open?为什么 onload 事件在使用 window.open 打开的选项卡上不起作用? 【发布时间】:2016-12-04 02:26:58 【问题描述】:

我打开一个新的空白标签。现在从这个选项卡我需要在新选项卡中打开一个网站。我这样做如下。我在其控制台中写道:

var wild = window.open("https://css-tricks.com/", "mywin", '');

效果很好。现在我可以使用wild.document 访问这个新窗口。现在我希望在加载其 dom 后在该页面上执行一些代码。我将onload 事件用作:

function foo()
    var mytext = wild.document.body.textContent;
    alert( mytext );

wild.addEventListener("load", foo);

但不幸的是,警报没有发生。我还尝试将事件侦听器作为explained in this answer 放在匿名自调用函数中,但这也不起作用。我也尝试过 ondomload 事件,但不幸的是那也没有用。所以,

为什么 onload 事件在使用 window.open 打开的选项卡上不起作用?以及如何让它正常工作?

【问题讨论】:

很可能是由于same origin policy。如果您正在加载外部网站,则无法在其上运行事件。 @Utkanos 如果我使用延迟 5 秒的 setTimeout 函数而不是 onload 函数,那么它可以完美运行。所以我猜这不是因为同源政策。 你试过了吗 wild.onload = foo;或 wild.addEventListener("load", foo, true); ? @oliv37 都试过了。但没有一个奏效。 我将新窗口 url 从 google.com 更改为其他内容以简化操作。 【参考方案1】:

如Detecting the onload event of a window opened with window.open 中所述,以下演示可以正常工作:

var wild;

window.addEventListener('DOMContentLoaded', function(e) 
  wild = window.open("myLocalStaticPage.html", "mywin", '');
  wild[wild.addEventListener ? 'addEventListener' : 'attachEvent'](
    (wild.attachEvent ? 'on' : '') + 'load', function (e) 
      alert("loaded")
    , false);
);

// the following handler only used for test purposes
document.addEventListener('click', function(e) 
  try 
    alert(wild);
   catch(err) 
    alert(err);
  
, false);

我在源页面添加了一个监听器,这样你就可以通过点击页面来测试 wild 变量的值。

对于静态页面没有问题。

但是,如果你需要打开经典的“http://google.com/”页面你会看到,点击起始页面会出现以下错误:

并且,从调试环境:

它们是什么意思?当您打开 google 页面时,google 会自行重定向,这是您无法控制的。

为什么会这样?为了避免刮擦......例如等等。

是否可以添加这样的监听器(负载)?是的,但我知道的唯一方法是创建 chrome 扩展、FF 扩展或 IE ..... 因为扩展 api (javascript) 为您提供了轻松执行此操作的可能性。

如果您对 Chrome api 感兴趣,可以查看 manifest 并查看名为 "content_scripts" 的部分的详细信息,例如:

"content_scripts": [
"matches":    ["*://*/*"],
"js":         ["content.js"],
"run_at": "document_end",
"all_frames": true

],

“run_at”参数在哪里:

控制何时注入 js 中的文件。可以是“document_start”、“document_end”或“document_idle”。默认为“document_idle”。

【讨论】:

我在控制台中添加了您的代码。它会打开新页面,但不会在 load 事件上显示警报。 @user31782 你用的是哪个网址?如果是“google.com”这正是我回答的内容。 @user31782 我创建了以下小提琴,您可以尝试一下:jsfiddle.net/5ueurpzg 以查看阻止错误消息。 你的 jsfiddle 只打开 google.com 它不显示任何块错误消息。 @user31782 你无法避免 CORS。这是一个安全问题。很抱歉,但是,CORS 政策一次又一次地得到了彻底的改进,没有办法逃脱。因此,“但是可以通过使用 window.opn 打开一个新的空白选项卡(无源)来绕过跨源错误”是错误的。我知道的唯一方法是创建一个插件,但这是另一个故事......再见【参考方案2】:

您正在加载一个外部站点,因此您应该得到一个跨域框架错误(我在 Chrome 控制台中测试您的代码时遇到过)。当我在 Firefox 中测试它时,窗口对象为空。在 Safari 中,对象是未定义的。

即使使用setTimeout,对象也为空或抛出错误,所以如果你说它使用setTimeout 有效,我会分享该代码。除非来源相同(因此相同的页面),否则不允许您访问另一个窗口的文档。至少这是我的理解。

我会在打开另一个窗口的第一页上有一个脚本:

<body>
 <script type="text/javascript">
   window.open('http://www.linktoyourotherpage.com/', 'mywin', '');
 </script>
</body>

以及用于操作文档的其他页面的脚本

<body onload="foo()">
  <script type="text/javascript">
    function foo() 
      var mytext = document.body.textContent;
      alert( mytext );
    
  </script>
</body>

【讨论】:

我没有收到跨源错误,因为我总是打开一个没有主机的空白新标签。正如您建议在另一页的body 上附加onload 事件。如何在 dom 实际加载之前将此事件附加到正文上? 完全按照我上面解释的方式进行 如何为其他页面添加脚本标签? 好吧,您将无法将脚本标签添加到 google.com。您可以将第一个 sn-p 添加到您的一个页面,将另一个 sn-p 添加到您的另一个页面。我认为打开 Google 是对您在自己的网站上所做的某事的某种测试。 我没有任何网站。我只是在空白新标签的控制台中测试代码。【参考方案3】:

请试试这个,

function foo() 
    var wild = window.open("http://google.com/", "mywin", '');
    wild.addEventListener("load", function()
        var mytext = wild.document.body.textContent;
        alert( mytext );        
    );

【讨论】:

我试过了,但onload事件从未执行过。 我遇到了同样的问题。我愿意:window.open (window.top.location, '_blank');这是从我自己的本地服务器提供的。 onload() 在刷新/重新加载页面时发生,因此 eonload 处理程序在那里。但是当我以编程方式执行上述操作时它不会触发。所以这是一个很好的问题,为什么不,如何让它触发【参考方案4】:

window.onload 事件在每个文档加载时触发。

var wild=null;

      function load() 
            if(wild !=null)
            
               alert("load event detected!  :"+wild.location.hostname+wild.location.pathname);
             
             else
               alert("not yet loaded");
          
      window.onload = load;

      wild = window.open("https://www.google.co.in/", "mywin", ''); // Security Exception raise due to Cross orgin security enabled google.co.in
     // wild = window.open("https://localhost:5555/test.html", "mywin", ''); //This will  work when same origin policy
     console.log("After Loading ...");

【讨论】:

URL 应该是同源或者 URL 服务器应该允许跨源。 // 由于为 google.co.in 启用了跨域安全性而引发安全异常 我没有收到跨域错误,因为我使用了新空白选项卡控制台中的代码。【参考方案5】:

您写道:“在它的控制台中,我写道:....”。这是否意味着您以交互方式打开它?如果是这样,则该窗口将打开。如果你在之后添加一个加载侦听器,它可能什么都不做,因为 DOM 已经加载。添加事件处理程序不会对已经发生的事件做出反应。

我遇到了同样的问题,想知道为什么当我以编程方式打开新标签时没有看到 onload-event 发生。我做的不同的是在控制台上记录一条消息。这是获取有关正在发生的事情的信息的更可靠的方法。可以出于多种原因阻止弹出警报,但不应阻止控制台消息。

但我没有在控制台上看到有关新窗口加载事件的消息,即使窗口确实打开了。这非常令人困惑,我(错误地)认为加载事件根本没有发生,因为我在控制台上什么也没看到。我想可能是因为我在另一个选项卡中加载了相同的 URL,其内容已经被浏览器缓存,因此不必“加载”(从服务器),因此不会导致 onload-event,因为它之前已经加载过了。

但事实证明解释更简单。加载事件确实发生了,但我没有看到关于它的控制台消息,因为......我正在查看 OPENER 窗口/选项卡的控制台!我没有看打开的选项卡的控制台。

每个选项卡/窗口都有自己的调试器 (-window)。来自选项卡的消息仅显示在其自己的调试器窗口的控制台中,而不显示在其他选项卡的控制台中。您可以打开多个调试器窗口,每个选项卡一个。这可能会让人感到困惑,因为很难知道哪个调试器窗口属于哪个浏览器窗口。

因此,在新选项卡中打开相同的 URL 后,我必须专注于该选项卡,然后在查看该选项卡时打开一个新的调试器窗口。然后我可以在该新控制台中看到有关加载事件处理程序的消息。我花了一些时间才弄清楚这一点,所以希望这可以帮助那些想知道为什么他们看不到 onload 事件的其他人。如果窗口打开,则事件可能确实发生了,您只是在查看错误的控制台。

是什么引起了我的困惑?可能是我们总是谈论“控制台”。这似乎意味着有(一个)“the”控制台。但是可以有多个控制台,在相同或不同时间打开,显示不同的消息。

这当然也适用于任何其他事件。仅仅因为您在正在查看的控制台上没有看到它的日志条目,并不一定意味着它没有发生。

【讨论】:

以上是关于为啥 onload 事件在使用 window.open 打开的选项卡上不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序里页面onload事件中。setData方法,为啥赋值给data,赋值不了?

为啥在<body>中加onload不能执行呢?

JS中使用innerHTML后元素的onclick事件为啥不能触发了?

如何使用JS清除 onload事件。

为啥我用js创建的image在canvas里显示不出来?

引导模式 onload 事件