只能通过 unsafeWindow 从 TamperMonkey 脚本触发鼠标悬停事件 - 为啥?

Posted

技术标签:

【中文标题】只能通过 unsafeWindow 从 TamperMonkey 脚本触发鼠标悬停事件 - 为啥?【英文标题】:Can only trigger mouseover event from TamperMonkey script via unsafeWindow - Why?只能通过 unsafeWindow 从 TamperMonkey 脚本触发鼠标悬停事件 - 为什么? 【发布时间】:2014-02-08 14:20:13 【问题描述】:

在现有网页上,通过 TamperMonkey 脚本,我想自动将鼠标悬停在图像上,等待“弹出窗口”(实际上是 )出现,然后单击该弹出窗口上的按钮。

现在,该代码从控制台触发了我所期望的鼠标悬停事件,并出现了一个“弹出窗口”。

$('div.photo.mpHover img').eq(0).mouseover()

在我的 TM 脚本中,此代码不会触发事件,除非我引用 unsafeWindow..

unsafeWindow.$('div.photo.mpHover img').eq(0).mouseover()

为什么会这样?我很困惑,因为例如从 TM 脚本模拟“点击”事件可以按预期工作而无需访问 unsafeWindow..

$('div.photo.mpHover img').eq(0).click()

【问题讨论】:

【参考方案1】:

jQuery 的 .click().mouseover() 只是 .trigger() 的快捷方式。 来自the docs:

任何事件处理程序附加.on() 或其快捷方法之一在相应事件发生时触发。但是,可以使用 .trigger() 方法手动触发它们。

还有:

注意:对于普通对象和除 window 以外的 DOM 对象,如果触发的事件名称与对象上的属性名称匹配,jQuery 将尝试调用该属性作为方法,如果没有事件处理程序调用 event.preventDefault()。

这在实践中意味着:

    .trigger(),或者它的一种快捷方法,只能可靠地作用于由 jQuery 设置的事件处理程序,而不是其他 javascript

    .trigger() 通常只有在 相同的 jQuery 实例,在相同的范围中调用时才会起作用。 用户脚本在不同的范围内运行,除非您注入其代码或使用 unsafeWindow 跳转范围。

    但是,如果目标元素有匹配的本地方法,例如click,jQuery 将默认尝试调用它。 许多元素都有原生的click 方法,但很少(¿none?)有原生的mouseover 方法。

    这就是为什么 jQuery .click()有时会在用户脚本中工作,即使不使用注入也是如此。但是,这并不可靠,并且由于尝试跨沙箱访问 JS 代码的安全限制,经常会失败。


最强大的解决方案是发送实际的鼠标事件(更新代码):

triggerMouseEvent ( $('div.photo.mpHover img').eq(0), "mouseover");

function triggerMouseEvent (jNode, eventType) 
    if (jNode  &&  jNode.length) 
        var clickEvent  = new MouseEvent (
            eventType, canBubble: true, cancelable: true
        );
        jNode[0].dispatchEvent (clickEvent);
    

旧方法:仍然有效,但has been deprecated。

triggerMouseEvent ( $('div.photo.mpHover img').eq(0), "mouseover");

function triggerMouseEvent (jNode, eventType) 
    if (jNode  &&  jNode.length) 
        var clickEvent = document.createEvent('MouseEvents');
        clickEvent.initEvent (eventType, true, true);
        jNode[0].dispatchEvent (clickEvent);
    


这在几乎所有情况下都有效,通常无需注入或unsafeWindow

有关更复杂的场景,请参阅"Choosing and activating the right controls on an AJAX-driven site"。

【讨论】:

看来 document.createEvent 已被弃用,因此我将重新编写您的代码示例以使用事件构造函数,不过感谢您花时间提供高质量的答案 Brock。 不客气。感谢您让我知道已弃用的代码。 @richardPlester 已修复。编辑已提交。

以上是关于只能通过 unsafeWindow 从 TamperMonkey 脚本触发鼠标悬停事件 - 为啥?的主要内容,如果未能解决你的问题,请参考以下文章

为啥用户脚本中的窗口(和 unsafeWindow)与 <script> 标记中的不同?

开发油猴脚本:给任意网页的选中文字涂色

有没有办法通过自定义事件传递额外的数据?

https(apache + ssl) 只能从 locahost 获得,如何配置通过域名访问它?

手机如何安装GreasyFork油猴js脚本?

如何从数据库中获取大量数据并通过输入输入将其显示到下拉列表过滤器中,但只能从数据库中选择