EventTarget接口
addEventListener:绑定事件的监听函数
target.addEventListener(type,listener,useCapture)
var btn=document.getElementById('btn');
btn.addEventListener('click',hello,false);
function hello(){console.log('ok');}
addEventListener方法可以为当前对象的同一个事件,添加多个监听函数。这些函数按照添加顺序触发,即先添加先触发。
如果为同一个事件多次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除。
false:监听函数只在冒泡阶段被触发;
true:监听函数只在捕获阶段被触发
removeEventListener:移除事件的监听函数
removeEventListener方法移除的监听函数,必须与对应的addEventListener方法的参数完全一致,而且必须在同一个元素节点,否则无效。
box.removeEventListener('click', hello2, true);
dispatchEvent:触发事件
只要有一个监听函数调用了Event.preventDefault(),则返回值为false,否则为true。
var box=document.getElementById('box');
box.addEventListener('click',hello,true);
box.addEventListener('click',hello2,true);
function hello(){console.log('ok');}
function hello2(){console.log('ok');}
var click=new Event('click');
box.dispatchEvent(click);
//ok
//ok
监听函数
事件发生时,程序所要执行的函数。
HTML标签的on-属性
<div onclick="console.log('ok');console.log('ok2');"></div>
<div onclick="hello()"></div>//正确,应该传入执行的代码,而不是函数
<div onclick="hello"></div>//错误
<script>
function hello(){console.log('ok');}
</script>
使用这个方法指定的监听函数,只会在冒泡阶段触发。
function hello(){console.log('ok');}
var box=document.getElementById('box');
box.setAttribute('onclick','hello()');//同上
Element节点的事件属性
div.onclick = function(event){
console.log('触发事件');
};
同一个事件只能定义一个监听函数,也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次。
使用这个方法指定的监听函数,只会在冒泡阶段触发。
addEventListener方法
推荐
this对象的指向
addEventListener方法指定的监听函数,内部的this对象总是指向触发事件的那个节点。因为监听函数被“拷贝”成了节点的一个属性,所以this指向节点对象。
var box=document.getElementById('box');
box.onclick=hello;
box.addEventListener('click', hello, false);
function hello(){
console.log(this);
}
//box
//box
如果将监听函数部署在Element节点的on-属性上面,this不会指向触发事件的元素节点。
<div onclick="hello()"></div>
<div id="box2"></div>
<script>
function hello(){
console.log(this);
}
var box2=document.getElementById('box2');
box2.setAttribute('onclick','hello()');
//window
//window
//相当于 box2.onclick=function(){hello();}
</script>
一种解决方法是,不引入函数作用域,直接在on-属性写入所要执行的代码。因为on-属性是在当前节点上执行的。
<div id="box"onclick="console.log(id);console.log(this.id)"></div>
//box
//box
事件的传播
一个事件发生后,会在不同的DOM节点传播。
主流浏览器支持标准的DOM事件处理模型:捕获型与冒泡型。
分成三个阶段:
捕获阶段:从window对象传导到目标节点;
目标阶段:在目标节点触发;
冒泡阶段:从目标节点传导到window对象。
<div id="p">
<div id="c"></div>
</div>
var c=document.getElementById('c');
var p=document.getElementById('p');
c.addEventListener('click', function(){console.log('c')}, true);
p.addEventListener('click', function(){console.log('p')}, true);
c.addEventListener('click', function(){console.log('c2')}, false);
p.addEventListener('click', function(){console.log('p2')}, false);
//点击内部的div
//p 捕获阶段
//c 目标阶段
//c2 目标阶段
//p2 捕获阶段
传播途径:window-document-html-body-…- body-html-document-window
IE使用自己的模型:冒泡型。
IE9以下不支持addEventListener()函数,IE9以上(包括IE9)支持,IE浏览器相应的要使用attachEvent()函数代替,它支持全系列的IE,但Chrome浏览器不支持attachEvent()。
ele.attachEvent(“onclick”, doSomething);
事件代理/事件委托
由于事件会传导到父节点,所以可以将监听函数定义在父节点上,由父节点统一处理多个子元素的事件。
var ul=document.querySelector('ul');
ul.onclick=function(event){
if(event.target.tagName.toLowerCase()==='li'){console.log(event.target);}
}
stopPropagation:使事件到当前节点为止,不再传播
<div>
<p>riuoweurew</p>
</div>
var li=document.querySelector('p');
var ul=document.querySelector('div');
li.addEventListener('click', hello1, false);
ul.addEventListener('click', hello2, false);//不会触发
function hello1(e){console.log('hello1');e.stopPropagation();}
function hello2(){console.log('hello2');}
//点击p
//hello1
但是,stopPropagation方法只会阻止当前监听函数的传播,不会阻止该节点上的其他click事件的监听函数。如果想要不再触发那些监听函数,可以使用stopImmediatePropagation方法。
stopImmediatePropagation方法阻止同一个事件的其他监听函数被调用。
如果同一个节点对于同一个事件指定了多个监听函数,这些函数会根据添加的顺序依次调用。只要其中有一个监听函数调用了stopImmediatePropagation方法,其他的监听函数就不会再执行了。
var li=document.querySelector('p');
var ul=document.querySelector('div');
li.addEventListener('click', hello1, false);
li.addEventListener('click', hello2, false);//会触发
ul.addEventListener('click', hello2, false);
function hello1(e){console.log('hello1');e.stopPropagation();}
function hello2(){console.log('hello2');}
//点击p
//hello1
//hello2 li上触发的click
//使用stopImmediatePropagation
var li=document.querySelector('p');
var ul=document.querySelector('div');
li.addEventListener('click', hello1, false);
li.addEventListener('click', hello2, false);//不会触发
ul.addEventListener('click', hello2, false);
function hello1(e){console.log('hello1');e.stopImmediatePropagation();}
function hello2(){console.log('hello2');}
//点击p
//hello1
Event对象
event =new Event(名称,配置)
配置是一个对象,有两个属性,bubbles表示是否冒泡,cancelable表示是否可取消
var ev=new Event('look',{bubbles:true,cancelable:false});
document.addEventListener('look', function(){console.log('ok');}, false);
document.dispatchEvent(ev);
//ok
event.bubbles:返回布尔值,表示是否会冒泡
event.eventPhase:返回整数,表示事件发生的阶段
0:还没发生
1:捕获阶段
2:目标阶段
3:冒泡阶段
event.cancelable:返回布尔值,表示事件是否可以取消
var ev=new Event('look',{bubbles:true,cancelable:false});
document.addEventListener('look', function(e){
console.log(e.cancelable,e.bubbles,e.eventPhase,e.target,e.currentTarget);
}, false);
document.dispatchEvent(ev);
//false true 2 document document
event.defaultPrevented:返回布尔值,表示是否调用了preventDefault方法
event.target:返回事件发生的节点,事件最初发生的节点
event.currentTarget:正在执行的监听函数所绑定的那个节点。
在监听函数中,currentTarget属性实际上等同于this对象。
var p=document.querySelector('p');
var div=document.querySelector('div');
p.addEventListener('click', function(e){
console.log(e.cancelable,e.bubbles,e.eventPhase,e.target,e.currentTarget,e.defaultPrevented);
}, false);
div.addEventListener('click', function(e){
console.log(e.cancelable,e.bubbles,e.eventPhase,e.target,e.currentTarget,e.defaultPrevented);
}, false);
//点击p
//true true 2 p p false
//true true 3 p div false
var p=document.querySelector('p');
var div=document.querySelector('div');
p.addEventListener('click', function(e){
e.preventDefault();
console.log(e.cancelable,e.bubbles,e.eventPhase,e.target,e.currentTarget,e.defaultPrevented);
}, false);
div.addEventListener('click', function(e){
console.log(e.cancelable,e.bubbles,e.eventPhase,e.target,e.currentTarget,e.defaultPrevented);
}, false);
//点击p
//true true 2 p p true
//true true 3 p div true
e.type:事件类型,e.detail:事件信息,e.timeStamp:事件发生时间戳,e.isTrusted:是否人为触发
var p=document.querySelector('p');
var div=document.querySelector('div');
p.addEventListener('click', function(e){
console.log(e.type,e.detail,e.isTrusted,e.timeStamp);
}, false);
div.addEventListener('click', function(e){
console.log(e.type,e.detail,e.isTrusted,e.timeStamp);
}, false);
//click 1 true 177572
//click 1 true 177572
对于dblclick事件,detail属性的值总是2
e.preventDefault()
取消浏览器对当前事件的默认行为,比如点击链接后浏览器跳转到指定地址,或者按一下空格键,页面滚动一段距离,该方法生效的前提是cancelable为true。
该方法与stopPropagation()不同。
自定义事件
var event=new Event('build');
elem.addEventListener('build',function(e){},false);
elem.dispatchEvent(event);
Event构造函数只能指定事件名,不能在事件上绑定数据。如果需要在触发事件的同时,传入指定的数据,需要使用CustomEvent构造函数生成自定义的事件对象。
var elem=document.querySelector('a');
var event=new CustomEvent('build',{detail:'helloworld'});
elem.addEventListener('build',function(e){console.log(e.detail);},false);
elem.dispatchEvent(event);
//helloworld