检测默认事件处理
是否可以检测到特定DOM事件是否绑定了任何事件处理程序(包括浏览器默认事件处理)-在Firefox的Gresemonkey代码中(EcmaScript 5.1 strict mode)?
到目前为止,我成功地在选定文本时取消了单击事件处理,但我想在以下所有情况下取消事件处理单击事件触发默认操作:
- 选择页面上的文本
- 显示上下文菜单(即单击鼠标右键)
- 后面有一个链接(左键单击
<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
条件的详尽列表 - 可从Firefox插件访问的非Java脚本方式
- 解释Firefox如何知道单击有效的
<a>
元素应触发重新加载新URL+如何无法从Java脚本/插件访问此逻辑
解决方案
此问题几乎与"How to do an action only when there is no default in Javascript / jQuery?"重复,只是作为Gresemonkey脚本编写者,您可以使用另一个(复杂)选项。
从您的问题看,您似乎想要为没有default action的节点设置default action,然后如果为给定事件触发任何其他事件处理程序,则中止该默认操作。对于这一点,没有"包罗万象的机制",而且几乎任何你尝试的技术都有可能在那里引起轰动。原因如下:Java脚本和Gresemonkey API都没有提供为给定节点列出事件的任何机制。有an old proposal,但从未实施过。
然而,Firefox外接程序可以通过nsIEventListenerService列出事件,因此有可能您可以为该部分编写一个与Gresemonkey接口的帮助器外接程序。详细信息超出了此问题的范围。
同样,除非设置了
event.defaultPrevented
,否则不存在从Event object检测事件链中先前事件的机制。(通常不会。)即使您可以列出节点X的事件侦听器,这对父节点上的回退侦听器也没有帮助。现代JS库可以,有时确实可以使任何旧节点都可以点击。和/或他们可以设置监听程序,例如,获取所有点击事件,但实际上不执行任何操作,除非原始目标是某个特定节点。
/li>
一个好的折衷策略是跟随另一个问题的线索,并且不对具有默认操作的节点执行任何操作。
要处理右击或居中单击,请选中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);
}
相关文章