js高级:事件绑定多方法,事件冒泡、事件捕获和阻止默认事件详解
本文为大家讲解js事件的高级性能和用法,包括事件绑定多方法、事件冒泡、阻止默认事件等。
dom事件流:事件冒泡、捕获和dom事件三个阶段
参考:https://blog.youkuaiyun.com/xllily_11/article/details/51134246
使用冒泡,还是使用捕获处理dom事件,可以使用addEventListener,参考:冒泡->冒泡和事件捕获的使用。
事件绑定多方法
传统js实现
同时调用感觉和一个onclick没啥区别,以分号隔开。两个方法按照先后顺序执行。
当然后也可以使用jquery的事件绑定。
jquery实现
<a href = "javascript:void(0);" id="testA">
要在文档加载完成后,绑定
$(function(){
$("#testA").click(function(e){
alert("ss");
//阻止冒泡
e.stopPropagation();
//阻止默认行为
e.preventDefault();
return false;
});
$("#testA").click(function(e){
alert("sss");
});
});
- 阻止冒泡、阻止默认行为、return false都不会阻止第二个绑定方法的执行;
解决方案:
可以使用jquery的动态事件绑定和解除绑定方法。
- 执行顺序:JS绑定的同步事件是按照绑定顺序执行的。
W3C对此有相关规范,原文内容如下:
Events which are synchronous (sync events) are treated as if they are in a virtual queue in a first-in-first-out model, ordered by sequence of temporal occurrence with respect to other events, to changes in the DOM, and to user interaction. Each event in this virtual queue is delayed until the previous event has completed its propagation behavior, or been canceled.
简单的翻译一下:
同步事件被看做有一个虚拟的先进先出的队列,按照绑定的时间的顺序进行DOM操作或者用户交互。每一个虚拟队列中的事件都会一直等待直到他前面的那个事件传播(冒泡或捕获)结束或者被取消。
href总结
onclick的事件被先执行,其次是href中定义的(页面跳转或者javascript)
同时存在两个定义的时候(onclick与href都定义了),如果想阻止href的动作,在onclick必须加上return false; 一般是这样写οnclick=”xxx();return false;”.
在href中定义的函数如果有返回值的话,当前页面的内容将被返回值代替
冒泡
如果在页面中重叠了多个元素,并且重叠的这些元素都绑定了同一个事件,那么就会出现冒泡问题。例如:
<body>
<div style="width:300px;height:300px;background-color:skyblue;">
<input type="button" value="button"/>
</div>
</body>
如果document、div、input三个元素绑定了同一个事件,就会产生
$(document).click(function(){
alert("document");
});
$("div").click(function(){
alert("div");
});
$(":button").click(function(){
alert("button");
});
});
当点击button时,会先弹出button、然后是div、然后是document
阻止冒泡
event.stopPropagation() : 所有上层的冒泡行为都将被取消
$(document).click(function(){
alert("document");
});
$("div").click(function(e){
e.stopPropagation();
alert("div");
});
$(":button").click(function(e){
e.stopPropagation();
alert("button");
});
冒泡和事件捕获的使用
参考 https://www.cnblogs.com/qq9694526/p/5653728.html
这是HTML结构
<div id="parent">
<div id="child" class="child"></div>
</div>
现在我们给它们绑定上事件(冒泡)
document.getElementById("parent").addEventListener("click",function(e){
alert("parent事件被触发,"+this.id);})
document.getElementById("child").addEventListener("click",function(e){
alert("child事件被触发,"+this.id)})
结果:
child事件被触发,child
parent事件被触发,parent
结论:先child,然后parent。事件的触发顺序自内向外,这就是事件冒泡。
现在改变第三个参数的值为true(事件捕获)
document.getElementById("parent").addEventListener("click",function(e){
alert("parent事件被触发,"+e.target.id);},true)
document.getElementById("child").addEventListener("click",function(e){
alert("child事件被触发,"+e.target.id)},true)
结果:
parent事件被触发,parent
child事件被触发,child
结论:先parent,然后child。事件触发顺序变更为自外向内,这就是事件捕获。
貌似没什么卵用,上一个利用事件冒泡的案例,反正我是经常会用到。
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
<li>item5</li>
<li>item6</li>
</ul>
需求是这样的:鼠标放到li上对应的li背景变灰。
利用事件冒泡实现:
$("ul").on("mouseover",function(e){
$(e.target).css("background-color","#ddd").siblings().css("background-color","white");
})
也许有人会说,我们直接给所有li都绑上事件也可以啊,一点也不麻烦,只要……
$("li").on("mouseover",function(){
$(this).css("background-color","#ddd").siblings().css("background-color","white");
})
是,这样也行。而且从代码简洁程度上,两者是相若仿佛的。但是,前者少了一个遍历所有li节点的操作,所以在性能上肯定是更优的。
还有就是,如果我们在绑定事件完成后,页面又动态的加载了一些元素……
$("<li>item7</li>").appendTo("ul");
这时候,第二种方案,由于绑定事件的时候item7还不存在,所以为了效果,我们还要给它再绑定一次事件。而利用冒泡方案由于是给ul绑的事件……
高下立判!
阻止默认行为
默认行为,常见的是点击超链接时的跳转,表单的提交,鼠标右击的系统菜单等等。
preventDefault():阻止默认行为
阻止超链接的跳转:
$("a").click(function(e){
e.preventDefault();
});
阻止表单的提交:
$("form:eq(0)").submit(function(e){
e.preventDefault();
});
阻止鼠标右键(contextmenu表示鼠标右键事件):
$( document ).contextmenu(function(e) {
e.preventDefault();
});
PS: contextmenu表示鼠标右键事件,用法与一般事件相同:
$(document).bind("contextmenu",function(){alert("鼠标右键")});
// 等效于:
$(document).contextmenu(function(e) {
alert("鼠标右键");
});
阻止冒泡并阻止默认行为
同时使用preventDefault()和stopPropagation()函数
$("a").click(function(e){
e.preventDefault();
e.stopPropagation();
});
或者,直接使用return false
$("a").click(function(e){
return false;
});