为什么在使用window.open打开的标签页中,onload事件无法工作?

8

我打开一个新的空白标签页。现在,我需要在一个新的标签页中打开一个网站。我按照以下方法操作:在该标签页的控制台中,我写入:

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);

但不幸的是,警报没有出现。我还尝试将事件监听器放在匿名自调用函数中,如这个答案中所解释的,但那也没用。我还尝试过ondomload事件,但不幸的是那也没用。所以,

为什么载入事件在使用window.open打开的标签上不起作用?如何让它正常工作?


2
很可能是由于同源策略的缘故。如果你正在加载外部网站,就无法在其上运行事件。 - Mitya
@Utkanos,如果我使用5秒的setTimeout函数代替onload函数,那么它就能完美地运行。所以我猜这不是因为同源策略的问题。 - user31782
你尝试过 wild.onload = foo; 或 wild.addEventListener("load", foo, true); 吗? - Olivier Boissé
@oliv37 尝试了两种方法,但都没有成功。 - user31782
我将新窗口的URL从google.com更改为其他内容,以使事情变得更简单。 - user31782
5个回答

6

检测使用window.open打开的窗口的onload事件所述,以下演示可以正常工作:

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/" 页面,你会看到,在起始页面上单击会出现以下错误:

enter image description here

而且,来自调试环境:

enter image description here

当你打开谷歌页面时,谷歌会自动重定向,这是无法控制的。这意味着什么?
为了避免网络爬虫等问题。
是否可以添加这样的监听器(负载)?
是的,但我所知道的唯一方法是创建一个Chrome扩展程序、FF扩展程序或IE扩展程序……因为扩展程序API(JavaScript)为您提供了无痛操作的可能性。
如果您对Chrome API感兴趣,可以查看清单,并详细了解名为"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。对于任何静态页面网站,onload事件都无法正常工作。 - user31782
如果静态页面几乎为空,那么你是正确的。onload事件只会触发一次,如果页面加载得太快,你是正确的。但是,对于像Google这样的网站......原因在答案中已经很好地描述了。让我知道。 - gaetanoM
1
@user31782 你无法避免CORS。这是一个安全问题。很抱歉,但是CORS政策已经不断得到改进,没有逃脱的办法。因此,“但是可以通过打开一个新的空白标签页(没有来源)来绕过跨域错误”是错误的。我知道的唯一方法是创建一个插件,但这是另外一个故事...再见。 - gaetanoM
好的,再见。 - user31782
显示剩余12条评论

1
您正在加载外部网站,因此应该会出现跨源框架错误(当我在Chrome控制台中测试您的代码时,确实如此)。在Firefox中测试时,窗口对象为null。在Safari中,该对象未定义。
即使使用setTimeout,对象仍为null或引发错误,因此如果您说使用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”实际加载之前,我该如何将此事件附加到“body”上? - user31782
请按照我以上所解释的方式精确地执行。 - kag359six
我该如何为另一个页面添加脚本标签? - user31782
好的,你不能在google.com上添加脚本标签。你可以将第一个代码片段添加到其中一个页面中,将另一个代码片段添加到另一个页面中。我假设打开Google是你在自己的网站上进行某种测试的一部分。 - kag359six
我没有任何网站。我只是在一个空白的新标签页的控制台中测试代码。 - user31782

0
你写道:“我在它的控制台中输入:……”,这是指你以交互方式打开它吗?如果是这样,那么窗口将会打开。如果之后你向其中添加一个加载监听器,那么可能什么也不会发生,因为DOM已经加载完成了。添加事件处理程序不能对已经发生的事件做出反应。
我曾经与同样的问题搏斗,想知道为什么当我编程打开一个新标签时却没有看到onload-event发生。我的不同之处在于我记录了一条控制台消息。这是获取有关正在发生的信息的更可靠的方法。警告弹出框可能会由于许多原因而被阻止,但控制台消息则不会。
但是,即使窗口正确打开,我也没有在控制台上看到有关新窗口加载事件的消息。这非常令人困惑,我错误地认为加载事件根本没有发生,因为我在控制台上没有看到任何内容。我认为可能是因为我在另一个标签中加载了相同的URL,浏览器已经缓存了其内容,因此不必从服务器“加载”,因此不会引起onload事件,因为早先已经加载过了。

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

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

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

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

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


0

当文档加载完成时,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服务器应该允许跨域。// 安全异常引发由于跨域安全启用为https://google.co.in。 - tsb
我没有遇到跨域错误,因为我在新的空白标签页的控制台中使用了这段代码。 - user31782

0
请尝试这个:
function foo() {
    var wild = window.open("http://google.com/", "mywin", '');
    wild.addEventListener("load", function(){
        var mytext = wild.document.body.textContent;
        alert( mytext );        
    });
}

我尝试过这个,但是onload事件从未被执行。 - user31782
我遇到了同样的问题。我执行以下代码:window.open(window.top.location, '_blank'); 这段代码是从我的本地服务器提供的。当刷新/重新加载页面时,onload()会触发处理程序。但是当我以编程方式执行上述操作时,它不会触发。所以这是一个好问题,为什么不会触发,如何使其触发。 - Panu Logic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接