热键插件即使弹窗被阻止也能打开新窗口?

5
如果按下"F2",我希望打开一个新窗口。以下代码在Firefox中会给我返回"newWindow is null"错误信息。如果我不使用弹出窗口拦截器,它就能正常工作。IE也是如此。即使启用了弹出窗口拦截器,它在Chrome中也能正常工作。
使用jstree pre 1.0 stable
            hotkeys: {
                "f3" : function () {
                url = "http://www.vse.cz";
                var newWindow = window.open(url, '_blank');
                newWindow.focus();
                return false;

            },

问题1: 我能否使热键插件在所有浏览器上都能正常工作,这样用户就不需要更改设置了?

问题2: 为什么使用JavaScript而不是target打开新窗口在火狐浏览器中没有任何问题?这是因为它是一个链接而不是使用热键插件吗?


我的理解是上面页面的脚本以某种方式操纵用户点击链接时发生的事情。它改变了点击的属性,使浏览器“不知道”它是新窗口,因此可以绕过弹出窗口拦截器。
在我的情况下,我使用纯JS函数由其他东西触发,而不是用户点击。而且“我的函数”不会改变任何HTML对象的属性。我认为这就是区别所在。我不确定我是否正确。
1个回答

7

很遗憾,除非禁用弹出窗口拦截器,否则您无法在按键时打开新窗口。

IE、Firefox和Chrome中弹出窗口拦截器的工作方式(从高层次来看)是通过浏览器(在遇到window.open调用时)向上遍历JavaScript调用堆栈,以确定当前函数是否为事件处理程序或被调用的函数之一。换句话说,它会找出当前函数是否正在执行,因为用户执行了触发DOM事件的操作。

如果是这样,那么允许弹出窗口;否则将其阻止。但是,哪些事件有资格作为“允许弹出窗口”的事件因浏览器而异。 Mozilla默认情况下,只有changeclickdblclickmouseupresetsubmit有资格。(我认为IE也类似。)

作为其他类型事件的事件处理程序(例如您的情况下的keydown/keyup/keypress),不符合特殊弹出窗口的条件,这意味着您的弹出窗口被阻止,这就是为什么调用window.open返回null的原因。

然而,Chrome认为keydown事件有资格允许打开弹出窗口,这就是为什么您的脚本在该浏览器中有效的原因。

这里有一个简化的示例来演示它的工作原理。 这个演示:

  • 定义一个名为spawn()的函数,该函数调用window.open来打开弹出窗口。
  • 在页面加载时立即调用spawn()。由于调用是从全局范围进行的,因此所有浏览器都会阻止该调用;它不是从事件处理程序中调用的。
  • 将一个函数附加到window.onkeydown,该函数调用spawn()。如果在Chrome中按下任意键,则允许弹出窗口,因为它允许从keydown处理程序中弹出窗口。在IE和Firefox中,弹出窗口将被阻止,因为这些浏览器不允许从键盘事件中弹出窗口。
  • 将一个事件处理程序附加到链接,该处理程序调用spawn()。单击链接时,在所有浏览器中都将允许弹出窗口,因为对window.open的调用可以追溯到click事件的事件处理程序。
正如你现在所看到的,没有任何操作可以操纵事件属性或者“欺骗”浏览器,使其不知道有一个新窗口存在。允许弹出式窗口从链接点击中打开的行为是有意设计的,理论上认为如果你点击了某个东西,那么很可能你希望看到弹出窗口中的内容。然而,当在你没有进行任何操作(比如全局范围)的地方调用window.open时,你很可能对自动启动的弹出式窗口中的任何[广告]都没有兴趣

这样,弹出式窗口拦截器可以防止令人讨厌的东西(自动启动的广告),同时还允许页面在用户请求时打开弹出式窗口。


@josh:非常好的解释,谢谢。那么contextmenu http://www.jstree.com/documentation/contextmenu 在哪里调用/因为鼠标点击而被触发的函数呢?我使用热键插件时遇到了相同的行为。 - Radek
1
@Radek:contextmenu事件虽然在逻辑上是鼠标单击事件,但它不在允许的事件列表中,所以行不通。 (还要考虑到contextmenu不一定是由鼠标单击触发的--用户可能会按下上下文菜单键或Shift+F10。)此外,您无法使用click处理程序捕获右键单击(请注意,如果您左键或中键单击,则数字会更改,但如果您右键单击,则不会更改)。 - josh3736
我不确定我是否理解正确。所以,如果我使用鼠标左键单击,window.open仍然无法工作? - Radek
@Radek:contextmenu 通常是由右键单击触发的;click 是由左键或中键单击触发的。您可以从 click 事件打开弹出窗口,但无法从 contextmenu 事件打开。 - josh3736
我是否可以仅通过左键单击触发“contextmenu”? - Radek
1
Native contextmenu DOM事件只在右键单击时触发。如果您要使用jQuery的事件处理程序触发机制($(element).trigger('contextmenu')),则需要意识到您实际上正在调用附加到事件的每个函数,但是您并没有导致本机DOM事件被触发。弹出规则基于调用触发jQuery事件处理程序的函数的本机DOM事件。规则不基于触发的jQuery事件应用。 - josh3736

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