为啥 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,赋值不了?