在外部委托调用中确定事件是否为 defaultPrevented

Determine whether event is defaultPrevented in external delegate call

鉴于两个 jQuery 函数直接和通过委托绑定到一个元素。

$("a").on("click", function (e) {
    console.log(e.isDefaultPrevented()); // returns false.
    // TODO: Determine whether the other function isDefaultPrevented.
});

$("body").on("click", "a", function (e) {
    e.preventDefault();
    console.log("I am a delegated call");
});

如何在直接绑定函数中判断e.preventDefault();是否在委托函数中被调用?

理论上我可以遍历 DOM 并使用 $._data() 检查任何绑定的事件处理程序,并使用 /preventDefault\(\)/.test(handler) 将函数解析为字符串,但这是非常不明智的,因为它两者都会很昂贵,并且 $._data() 也被标记为折旧以支持私有 data_priv 变量。

有什么想法吗?

How would I determine in the directly bound function whether e.preventDefault(); has been called in the delegated function?

不能,因为尚未调用委托函数。您的直接处理程序将始终在匹配相同元素的委托处理程序之前被调用,因为委托处理程序不会 运行 直到事件冒泡到它,即 after直接处理程序已经尝试过了。

如果您可以控制这两个处理程序,那么您当然可以在它们之间建立通信:

(function() {
    $("a").on("click", function (e) {
        var $this = $(this);

        // Direct handler is always called first
        $this.data("prevented", false);
        setTimeout(function() {
            if ($this.data("prevented")) {
                // Prevented by delegated handler
            }
        }, 0);
    });

    $("body").on("click", "a", function (e) {
        e.preventDefault();
        $(this).data("prevent", true);
    });
})();

当然,到那个时候如果你想在直接处理程序中阻止它已经太晚了。

示例:

$("#container div").on("click", function(e) {
  snippet.log("direct called");
  var $this = $(this);
  $this.data("prevent", false);
  setTimeout(function() {
    if ($this.data("prevent")) {
      snippet.log("direct detected default prevented");
    } else {
      snippet.log("direct detected default NOT prevented");
    }
  }, 0);
});
$("#container").on("click", "div", function(e) {
  var $this = $(this);
  snippet.log("delegated called");
  if ($this.hasClass("prevent")) {
    e.preventDefault();
    $this.data("prevent", true);
    snippet.log("delegated prevented default");
  }
});
<div id="container">
  <div class="prevent">
    Click me and the delegated handler will prevent the default.
  </div>
  <div>
    Click me and the delegated handler <strong>won't</strong>
    prevent the default.
  </div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

如果你不这样做,它会变得更棘手。您可以使用 setTimeout 等到委托处理程序 运行s 之后进行检查,但随后您必须检查 e.originalEvent,而不仅仅是 e,这会带来交叉-浏览器问题:

$("a").on("click", function (e) {
    setTimeout(function() {
        if (e.originalEvent.isDefaultPrevented()) {
            // Yes, the delegated handler prevented it
        }
    }, 0);
});

...因为委托处理程序中的 e 对象与直接处理程序中的 e 对象不同; jQuery 创建单独的事件(使用相同的底层原始事件)。

当然,您可以解决这些跨浏览器问题;检查 e.originalEvent.isDefaultPrevented 并在存在时使用它,如果不查看 e.originalEvent.returnValue(IE 特定的东西)...

不过,如果需要的话,在直接处理程序中阻止它仍然为时已晚。

示例:

$("#container div").on("click", function(e) {
  snippet.log("direct called");
  setTimeout(function() {
    // Cross-browser issue here
    if (e.originalEvent.isDefaultPrevented()) {
      snippet.log("direct detected default prevented");
    } else {
      snippet.log("direct detected default NOT prevented");
    }
  }, 0);
});
$("#container").on("click", "div", function(e) {
  snippet.log("delegated called");
  if ($(this).hasClass("prevent")) {
    e.preventDefault();
    snippet.log("delegated prevented default");
  }
});
<div id="container">
  <div class="prevent">
    Click me and the delegated handler will prevent the default.
  </div>
  <div>
    Click me and the delegated handler <strong>won't</strong>
    prevent the default.
  </div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>