Javascript 即使某个元素停止传播,我如何处理页面中任意位置的单击?
我们正在开发一个JavaScript工具,其中包含较旧的代码, 因此,我们无法重新编写整个工具 现在,在底部添加了一个固定位置的菜单,客户非常希望它有一个切换按钮来打开和关闭菜单, 但当用户开始在菜单外执行操作时(例如,当用户返回页面并选择某个内容或单击表单字段时),需要自动关闭 这在技术上可以与Javascript 即使某个元素停止传播,我如何处理页面中任意位置的单击?,javascript,jquery,events,jquery-events,Javascript,Jquery,Events,Jquery Events,我们正在开发一个JavaScript工具,其中包含较旧的代码, 因此,我们无法重新编写整个工具 现在,在底部添加了一个固定位置的菜单,客户非常希望它有一个切换按钮来打开和关闭菜单, 但当用户开始在菜单外执行操作时(例如,当用户返回页面并选择某个内容或单击表单字段时),需要自动关闭 这在技术上可以与正文上的点击事件一起工作,任何点击都会触发, 但是,旧代码中有许多项,其中在内部链接上处理了单击事件,并将返回false添加到单击功能中,以使站点不继续使用链接的href标记 很明显,像这样的通用函数确
正文
上的点击
事件一起工作,任何点击都会触发,
但是,旧代码中有许多项,其中在内部链接上处理了单击事件,并将返回false
添加到单击功能中,以使站点不继续使用链接的href
标记
很明显,像这样的通用函数确实可以工作,但当单击返回false停止传播的内部链接时就不行了
$('body').click(function(){
console.log('clicked');
});
我有没有办法强制身体点击事件,
或者有没有其他方法可以让菜单显示出来,使用一些全局单击事件或类似的事件?
无需重写应用程序中多年前创建的所有其他单击。
这将是一项艰巨的任务,特别是因为我不知道如何重写它们,而不返回false,但仍然不让它们转到它们的
href
我想这就是您需要的:
$("body").trigger("click");
这将允许您从任何位置触发body click事件。您真正想要做的是为事件的捕获阶段绑定事件处理程序。然而,据我所知,IE中不支持这一点,所以这可能没有多大用处 相关问题:
$('*').click(function(event) {
if (this === event.target) { // only fire this handler on the original element
alert('clicked');
}
});
请注意,如果您的页面中有很多元素,那么这将非常缓慢,而且对于动态添加的任何内容都不起作用。现代DOM实现中的事件有两个阶段,捕获和冒泡。捕获阶段是第一阶段,从文档的
defaultView
流到事件目标,然后是冒泡阶段,从事件目标流回到defaultView
。有关详细信息,请参阅
要处理事件的捕获阶段,需要将addEventListener
的第三个参数设置为true
:
document.body.addEventListener('click', fn, true);
不幸的是,正如Wesley提到的,事件的捕获阶段无法可靠地处理,或者根本无法在旧浏览器中处理
一种可能的解决方案是处理mouseup
事件,因为单击的事件顺序是:
mouseup
事件,那么这是一种方法(可以说是更好的方法)。另一件需要注意的事情是,许多(如果不是大多数的话)(如果不是全部的话)UI菜单在鼠标按下时消失。与Andy E合作,这就是原力的黑暗面:
var _old = jQuery.Event.prototype.stopPropagation;
jQuery.Event.prototype.stopPropagation = function() {
this.target.nodeName !== 'SPAN' && _old.apply( this, arguments );
};
示例:
记住,如果所有事件都是通过jQuery绑定的,那么您可以在这里处理这些情况。在本例中,如果不处理
,我们只调用原始的.stopPropagation()
你不能阻止阻止,不 您可以做的是,在代码中手动重写这些事件处理程序。这是一项棘手的工作,但如果您知道如何访问存储的处理程序方法,您可以解决这个问题。我玩了一会儿,结果是:
$( document.body ).click(function() {
alert('Hi I am bound to the body!');
});
$( '#bar' ).click(function(e) {
alert('I am the span and I do prevent propagation');
e.stopPropagation();
});
$( '#yay' ).click(function() {
$('span').each(function(i, elem) {
var events = jQuery._data(elem).events,
oldHandler = [ ],
$elem = $( elem );
if( 'click' in events ) {
[].forEach.call( events.click, function( click ) {
oldHandler.push( click.handler );
});
$elem.off( 'click' );
}
if( oldHandler.length ) {
oldHandler.forEach(function( handler ) {
$elem.bind( 'click', (function( h ) {
return function() {
h.apply( this, [{stopPropagation: $.noop}] );
};
}( handler )));
});
}
});
this.disabled = 1;
return false;
});
示例:
注意,上面的代码只适用于jQuery1.7。如果这些单击事件与早期jQuery版本或“内联”绑定,您仍然可以使用代码,但需要以不同的方式访问“旧处理程序”
我知道我在这里假设了很多“完美世界”场景,例如,这些句柄显式调用.stopPropagation()
,而不是返回false
。因此,这可能仍然是一个无用的学术例子,但我觉得要说出来:——)
编辑:嘿,
返回false
可以很好地工作,事件对象也是以同样的方式访问的。您可以使用jQuery在文档DOM上添加事件侦听器
$(文档)。在(“单击”)上,函数(){
console.log('clicked');
});代码>
这是关键(vs.evt.target)。参见示例
document.body.addEventListener(“单击”,函数(evt){
console.dir(this);
//注:evt.target可以是嵌套元素,而不是主体元素,从而导致缺火
console.log(evt.target);
警报(“身体点击”);
});代码>
这是一个标题。
这是一段。
演示
如果dom中嵌套得更深的东西阻止了事件传播,会不会触发这种情况?我认为问题在于,单击事件被某些链接上的事件处理程序返回false吞没了,而不是一开始就无法生成单击事件。通过$(“*”)可以很容易地修复动态问题,函数(){});但无论如何,这是一个坏主意。对于任何想知道是否可以使用它的人,这里是caniuse页面:简短的回答是可以的,只要你不关心IE8
document.body.addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
console.log('clicked ;)');
}
});