我们正在开发一个包含较旧代码的JavaScript工具, 所以我们不能重写整个工具。
现在,添加了一个固定在底部的菜单,客户非常希望有一个切换按钮来打开和关闭菜单, 除了关闭需要在用户开始在菜单旁边执行操作时自动发生,例如,当用户返回页面,并选择某些内容或点击表单字段时。
这在技术上可以与click
上的body
事件一起使用,触发任何点击,
但旧代码中有许多项目,其中在内部链接上处理了点击事件,并且return false
已添加到点击功能中,以便网站无法继续链接的href
标签
很明显,像这样的通用函数确实有效,但是当点击内部链接时,返回false会停止传播。
$('body').click(function(){
console.log('clicked');
});
有没有办法可以强制进行身体点击事件, 或者是否有其他方式可以让菜单消失,使用一些全局点击事件或类似的东西?
无需重写多年前创建的应用程序中的所有其他点击。
这将是一项怪物任务,特别是因为我不知道如何重写它们,而不返回false,但仍然不让它们转到href
。
答案 0 :(得分:56)
现代DOM实现中的事件有两个阶段,捕获和冒泡。捕获阶段是第一阶段,从文档的defaultView
流向事件目标,然后是冒泡阶段,从事件目标流回defaultView
。有关详细信息,请参阅http://www.w3.org/TR/DOM-Level-3-Events/#event-flow。
要处理事件的捕获阶段,您需要将addEventListener
的第三个参数设置为true
:
document.body.addEventListener('click', fn, true);
可悲的是,正如Wesley所说,在旧浏览器中无法可靠地处理事件的捕获阶段。
一种可能的解决方案是处理mouseup
事件,因为点击的事件顺序是:
如果您确定没有处理程序取消mouseup
事件,那么这是一种方式(并且可以说是一种更好的方法)。另外需要注意的是,如果不是大多数(如果不是全部的话),UI菜单会在鼠标按下时消失。
答案 1 :(得分:6)
与 Andy E 合作,这是力量的黑暗面:
var _old = jQuery.Event.prototype.stopPropagation;
jQuery.Event.prototype.stopPropagation = function() {
this.target.nodeName !== 'SPAN' && _old.apply( this, arguments );
};
示例:http://jsfiddle.net/M4teA/2/
请记住,如果所有事件都是通过jQuery绑定的,那么您可以在这里处理这些情况。在此示例中,如果我们不处理.stopPropagation()
,我们只需调用原始<span>
。
你无法阻止预防,没有。
您可以做的是,在代码中手动重写这些事件处理程序。这是一个棘手的业务,但如果您知道如何访问存储的处理程序方法,您可以解决它。我玩了一下,这是我的结果:
$( 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;
});
注意,上面的代码只适用于jQuery 1.7。如果这些点击事件与早期的jQuery版本或“内联”绑定,您仍然可以使用代码,但您需要以不同方式访问“旧处理程序”。
我知道我在这里假设了许多“完美的世界”场景,例如,这些句柄明确地调用.stopPropagation()
而不是返回false
。所以它仍然可能是一个无用的学术范例,但我觉得它会出来: - )
编辑:嘿,return false;
工作得很好,事件对象也以同样的方式访问。
答案 2 :(得分:3)
如果你确定这是第一个事件处理程序工作,那么这样的事情可能会起到作用:
$('*').click(function(event) {
if (this === event.target) { // only fire this handler on the original element
alert('clicked');
}
});
请注意,如果您的页面中有很多元素,那么这将非常慢,并且对于动态添加的任何内容都不起作用。
答案 3 :(得分:2)
您真正想要做的是将事件处理程序绑定到事件的捕获阶段。但是,据我所知,这在IE中是不受支持的,所以这可能不是那么有用。
http://www.quirksmode.org/js/events_order.html
相关问题:
答案 4 :(得分:2)
this
是密钥(相对于evt.target)。参见示例。
document.body.addEventListener("click", function (evt) {
console.dir(this);
//note evt.target can be a nested element, not the body element, resulting in misfires
console.log(evt.target);
alert("body clicked");
});
<h4>This is a heading.</h4>
<p>this is a paragraph.</p>
答案 5 :(得分:1)
您可以使用jQuery在文档DOM上添加事件侦听器。
$(document).on("click", function () {
console.log('clicked');
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
答案 6 :(得分:0)
我认为这就是你所需要的:
$("body").trigger("click");
这将允许您从任何地方触发身体点击事件。
答案 7 :(得分:0)
document.body.addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
console.log('clicked ;)');
}
});
演示