【问题标题】:Detect default event handling检测默认事件处理
【发布时间】:2013-03-17 11:17:45
【问题描述】:

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

So far I managed to cancel my click event handling when a text is selected, but I would like to cancel my event handling in all following situations where click event triggers a default action:

  • 在页面上选择文本
  • 显示上下文菜单(即右键单击)
  • 一个链接被点击(左键点击<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/插件访问此逻辑

【问题讨论】:

  • 不,没有包罗万象的解决方案。我只能想到挂钩document 并检查是否针对特定事件阻止了默认值(如果停止传播,这甚至将不起作用)
  • @Bergi 在我的情况下,如果传播停止就可以了,我只想在浏览器中没有其他任何事情想要做任何事情的情况下执行我的点击事件处理
  • 然后将if (! e.defaultPrevented) 添加到您的toggleHighlight 函数中。
  • @Bergi 感谢其中 1 个条件,仍然需要类似 if (e.thereIsADefault)

标签: javascript event-handling dom-events greasemonkey ecmascript-5


【解决方案1】:

这个问题几乎是 "How to do an action only when there is no default in Javascript / jQuery?" 的重复问题,除了作为 Greasemonkey 脚本编写者还有一个(复杂的)选项可供您使用。

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

  1. javascript 和 Greasemonkey API 都没有提供任何机制来列出给定节点的事件。有an old proposal,但从未实现。

    然而, Firefox 插件可以通过nsIEventListenerService 列出事件,所以有一个可能性您可以为该部分编写一个辅助插件,即与 Greasemonkey 接口。细节(方式)超出了这个问题的范围。

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

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


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

因此,您可以将以下 sn-ps 添加到您的检查中:

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

【讨论】:

  • 很久没有更好的答案了,所以我终于接受了这个——无论如何我放弃了我的 Greasemonkey 脚本,我现在使用三次点击 + ::-moz-selection 以令人赏心悦目的颜色突出显示文本跨度>
猜你喜欢
  • 2011-08-12
  • 2016-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多