1.冒泡:触发一个元素的事件时,该事件会向上(向父元素)传递
<div class="parent">
<ul class="news-list">
<li><a href='#'>新闻</a></li>
<li><a href='#'>体育</a></li>
<li><a href='#'>财经</a></li>
</ul>
</div>
如上,触发<li>的点击事件时,同时也会触发<news-list>和<parent>...一直到<body>的点击事件,前提是这些父元素要绑定了点击事件且没有阻止冒泡。
2.捕获 :与冒泡相反,触发元素的事件时,会从根元素开始向目标元素一直传递事件。
3.事件委托(代理):
事件委托就利用了冒泡的机制,试想一下,我有一个<ul>,里面有成百上千个<li>,每个<li>对应一个点击链接,那么按照常规做法,我需要循环这些<li>,依次添加点击事件,这对性能是有很大影响的,如下:
// 常规做法 遍历 li中的a标签 添加事件
for(child of document.getElementsByClassName('news-list')[0].childNodes){
if(child.childNodes.length){
child.childNodes[0].addEventListener('click',function(e){
console.log(this);
//e.stopPropagation(); //阻止冒泡 不会传递回父元素
})
}
}
另外,如果在这之后我们添加了新的<li>,新增的结点是不会注册该事件的
let LiItem=document.createElement("li")
LiItem.innerHTML = "<a href='#'>新增</a>"
let dom = document.getElementsByClassName('news-list')[0];
dom.appendChild(LiItem) //没有触发事件
这时候事件委托(代理)就派上用场了,首先,事件委托的原理就是冒泡机制。在上述场景中,我们不再需要循环遍历<li>去注册事件,而是仅仅给父元素parent注册一个事件。
// 先给父元素绑定事件
document.getElementsByClassName('parent')[0].addEventListener('click',function(e){
parFun(e);
},false);
然后看看parFun做了什么
function parFun(e) {
var e = e || window.event;
op = e.target;
console.log(e); //事件
console.log(op); //触发事件的元素
// 点到a才触发
if(op.nodeName.toLowerCase()=='a'){
console.log(op.innerText);
}
}
分析:首先要确认,这时候只有最外层的parent注册了点击事件,<li>甚至<ul>都没有注册事件,那么当我们点击<li>时,会依次触发父元素的点击事件,父元素ul没有注册点击事件,那么继续往上传递,找到<div class='parent'>,触发事件。这时候可以获取事件源e和触发事件的元素op,然后可以利用op进行判断是否要触发。