4

是否可以在 Firefox 的 Greasemonkey 代码EcmaScript 5.1 严格模式中检测特定 DOM 事件是否绑定了任何事件处理程序(包括浏览器默认事件处理) ?

到目前为止,我设法在选择文本时设法取消了点击事件处理,但是我想在以下所有情况下取消事件处理,而单击事件触发默认操作:

  • 选择页面上的文本
  • 显示上下文菜单(即右键单击)
  • 跟随一个链接(左键单击<a>
  • 表单元素被操作(文本框获得焦点,光标开始闪烁,单选按钮被选中,...)
  • 其他一些处理事件的 JavaScript 代码(例如显示弹出帮助对话框)

是否有一个包罗万象的机制,还是我需要在我的代码中明确拼写所有情况?

以下代码是我如何检测到选择发生:

var toggleHighlight = function(){
    var oldTargt;
    return function(e){
        targt = e.target;
        sel = window.getSelection();
        if (!sel.isCollapsed && sel.containsNode(targt, true)) {
            return;
        }
        ...
        oldTargt = targt;
}()
document.addEventListener('click', toggleHighlight);

注意:
- 我不想停止使用我的脚本传播,如果事件将被传播到其他处理程序,我想停止我的脚本。 - 如果JQuery-event-handlers-only解决方案没有捕获默认浏览器事件处理程序
,我对它们不感兴趣。- 如果此功能确实不存在,请引用一些文章或博客,而不仅仅是您自己的观点。 - 欢迎提出特别建议,但我主要对通用解决方案的存在感兴趣。

更新:可接受的解决方案包括:

  • if我需要检查的详尽(ish)条件列表
  • 从 Firefox 插件访问的非 JavaScript 方式
  • 解释 Firefox 如何知道单击有效<a>元素应触发重新加载新 URL + 如何无法从 javascript/plugins 访问此逻辑
4

1 回答 1

3

这个问题几乎与“仅在 Javascript / jQuery 中没有默认值时如何执行操作?”重复。,除了作为 Greasemonkey 脚本编写者,还有一个(复杂的)选项可供您使用。

从您的问题来看,您似乎想为没有节点的节点设置默认操作,然后在任何其他事件处理程序为给定事件触发时中止该默认操作。对此没有“包罗万象的机制”,您尝试的几乎任何技术都可能会破坏某些页面。原因如下:

  1. javascript 和 Greasemonkey API 都没有提供任何机制来列出给定节点的事件。有一个旧提案,但从未实施。

    但是, Firefox 插件可以通过nsIEventListenerService列出事件,因此您可以为该部分编写一个与 Greasemonkey 接口的辅助插件。细节(方式)超出了这个问题的范围。

  2. 同样,没有机制可以从Event object检测事件链中的先前事件,除非event.defaultPrevented已设置。(通常不会。)

  3. 即使您可以列出节点 X的事件侦听器,这也无助于父节点上的后备侦听器。现代 JS 库可以而且有时确实可以使任何旧节点可点击。和/或他们可能会设置一个监听器,比如说,document会获取所有点击事件,但实际上除了原始目标是某个特定节点时不会做任何事情。


一个好的折衷策略是跟随其他问题的引导,不对具有默认操作的节点做任何事情。
要处理右键单击或中心单击,请选中event.which.

因此,您可以将以下代码段添加到您的检查中:

return function(e){
    targt   = e.target;
    sel     = window.getSelection();

    if (e.which != 1) {
        return; //-- Abort on anything that is not a left-click.
    }
    if (e.defaultPrevented) {
        return; //-- The one time we know that some other handler fired.
    }
    if (isInteractiveElement (targt) ) {
        // Do nothing for elements that trigger browser actions
        return; 
    }
    ...

在哪里:

function isInteractiveElement (node) {
    var intElems = [
        //-- Must be uppercase
        "A", "BUTTON", "INPUT", "TEXTAREA", "VIDEO", "MAP", "OBJECT"
    ];
    if (intElems.indexOf (node.nodeName) >= 0) {
        return true;
    }
    else if (node.nodeName === "BODY") {
        return false;
    }

    return isInteractiveElement (node.parentNode);
}
于 2013-04-29T11:12:42.630 回答