背景:
在秋招海康威视面试时,面试官有问我这样一道题:
一个元素中有很多个元素,怎么样确定是点的哪个元素?
由于我对于事件委托的概念记不太清了,回答得不是很清楚,在这里整理一下。
事件委托
在红宝书中有如下概念:
事件流:描述的是从页面中接收事件的顺序;
事件冒泡(IE):事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点。
事件捕获:不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。用意在于事件达到预定目标前捕获它。
事件委托:对“事件处理程序过多”问题的解决方案就是事件委托。利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
解决问题
根据问题来设计场景,假设一个ul里面包裹五个li。我要点击不同li输出不同的结果。
<body>
<ul id="ulEvent">
<li id="sayHi">sayHi</li>
<li id="sayYes">sayYes</li>
<li id="sayNo">sayNo</li>
<li id="sayHa">sayHa</li>
<li id="sayEn">sayEn</li>
</ul>
<script>
window.onload=function(){
var ulEvent=document.getElementById("ulEvent");
ulEvent.onclick = function (ev) {
var ev = ev || window.event;
var target = ev.target || ev.srcElement; //普通浏览器或者ie
switch(target.id){
case 'sayHi' :
alert('Hi');
break;
case 'sayYes' :
alert('Yes');
break;
case 'sayNo' :
alert('No');
break;
case 'sayHa' :
alert('Ha');
break;
case 'sayEn' :
alert('En');
break;
}
}
}
</script>
</body>
注意:
Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement。
所以据此我可以回答面试官:可以用target来获得目标节点。
在获得target后添加控制台输出。
当我点击yes时,控制台输出:
能得到点击时的节点。
使用事件委托的好处:
1、显而易见的是可以减少注册事件;使其集中到父事件上
2、新添加的元素同样无需绑定也可以有事件:
<ul id="ulEve">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<button id="btn">添加li元素</button>
window.onload=function(){
var ulEvent=document.getElementById("ulEve");
var oLi=document.getElementsByTagName('li');
var btn=document.getElementById('btn');
ulEvent.onclick=function(ev){
var ev=ev||window.event;
var target=ev.target||ev.srcElement;
console.log(target);
console.log(target.nodeName) //这里输出的元素名称是全大写
if(target.nodeName.toLowerCase()=="li"){
alert('hi');
}
}
btn.onclick=function(){
var aLi=document.createElement('li');
aLi.innerHTML='6'
ulEvent.appendChild(aLi);
}
}
点击6的时候仍然say hi;