dom.addEventListener(type, listener[, useCapture])用于在当前节点或对象上,定义一个特定事件的监听函数listener。一旦这个事件发生,会执行监听函数。该方法没有返回值。但是监听函数不是立即执行,有时根据useCapture (可以为false或true)值,在事件的冒泡(false,默认值)或捕获阶段(true)去执行。
type:事件名称,大小写敏感。
listener:监听函数。事件发生时,会调用该监听函数。
useCapture:布尔值,表示监听函数是否在捕获阶段(capture)触发(参见后文《事件的传播》部分),默认为false(监听函数只在冒泡阶段被触发)。该参数可选。
<body>
<div style="width:200px;height:50px;background:aliceblue" id="div">
<button id="btn">点击</button>
</div>
</body>
let div=document.getElementById("div"),btn=document.getElementById("btn");
//阻止事件冒泡,div事件不在冒泡阶段触发
div.addEventListener("click",function(){console.log("div click");},true);//捕获阶段触发
btn.addEventListener("click",function(){console.log("btn click");}); //输出 div click; btn click
//以上dom接以下js
div.addEventListener("click",function(){console.log("div click");},false);//默认为false(监听函数只在冒泡阶段被触发)
btn.addEventListener("click",function(){console.log("btn click");}); //输出 btn click div click
window.onclick=function(){
console.log('window click');
}
div.addEventListener("click",function(){console.log("div click");},false);//默认为false(监听函数只在冒泡阶段被触发)
btn.addEventListener("click",function(){console.log("btn click");}); //输出 btn click div click window click
注意,浏览器总是假定click事件的目标节点,就是点击位置嵌套最深的那个节点(本例是
一个事件发生后,会在子元素和父元素之间传播(propagation)
捕获阶段 window 到目标节点 在捕获中,外部元素的事件会先被触发,然后才会触发内部元素的事件 ,从window到目标节点事件依次触发
目标阶段 事件在目标节点触发
冒泡阶段 目标节点传回window对象 从底层传回上层
这种三阶段的传播模型,使得同一个事件会在多个节点上触发。
阻止事件传播 如果希望事件到某个节点为止,不再传播,可以使用事件对象的stopPropagation方法。
在此附上一个很丑但是很好理解记忆的事件传播图解…
事件发生以后,会产生一个事件对象 作为参数传给监听函数 浏览器原生提供一个Event对象,所有的事件都是这个对象的实例,或者说继承了Event.prototype对象。
function callback(event) {
var tag = event.currentTarget.tagName;
console.log('Tag: ' + tag); // 没有任何输出
}
div.addEventListener('click', callback, false);
Event生成实例
event = new Event("click");
Event {
isTrusted: false
bubbles: false
cancelBubble: false
cancelable: false
composed: false
currentTarget: null
defaultPrevented: false
eventPhase: 0
path:[]
returnValue: true
srcElement: null
target: null
timeStamp: 3540258.5
type: "click"
[[Prototype]]: Event
}
综合事件传播,理解event的两个属性 Event.currentTarget,Event.target
以下猜猜输出顺序
<body>
<div id="div">
<button id="btn">点击</button>
</div>
</body>
let btn=$("#btn")[0],div=$("#div")[0];
//btn.addEventListener("click",true);
//这样写报错,要求第二个参数为对象Uncaught TypeError: Failed to execute 'addEventListener' on 'EventTarget': parameter 2 is not of type 'Object'
//点击btn ,默认冒泡
div.addEventListener("click",function(event){
console.log('div click');
},false)//父元素监听函数是冒泡阶段执行
btn.addEventListener("click",function(event){//看路径,看何时触发
console.log("btn click");
},true);//如果是true的话,事件直接到btn 子元素监听函数是捕获阶段执行
结果是 btn click div click
我一开始以为是div click btn click ,因为感觉子元素是事件捕获时触发的,而父元素(div)click被触发先于子元素(btn),其实是错的,根本原因在于,事件被触发时,监听函数不一定马上执行,监听函数执行时间也因为受ad listener,第三个参数决定。
这里父元素的为false,父元素监听函数在冒泡阶段执行的,子元素的第三个参数true 是表示子元素事件的监听函数 是在捕获阶段执行的
这个案例的核心说明了:事件 被触发了之后 ,如果用Addeventlistener 给元素绑定事件监听函数的话 ,它的监听函数不一定随着事件触发立即执行,涵盖了 Addeventlistener 绑定事件监听函数和事件传播原理。
参考 (阮一峰老师的事件教程 ) https://www.bookstack.cn/read/javascript-tutorial/docs-events-model.md