当我们在网页上进行交互时,会触发事件:例如某些内容上的点击、鼠标经过某个特定元素或者按下键盘上的某些按键。
当一个节点产生一个事件时,该事件会在元素结点与根节点之间按特定顺序传播,路径所经过的节点都会收到该事件,这个传播过程称为DOM事件流。
什么是事件流?
事件流就是从页面中接收事件的顺序。IE和Netscape提出了完全相反的事件流概念,IE事件流是**事件冒泡**,而Netscape事件流是**事件捕获**。
事件冒泡和事件捕获?
IE提出事件流是事件冒泡,即从下到上,从目标触发的元素逐渐向上传播,直到window对象。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210623172427525.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzUwMDkzNzg1,size_16,color_FFFFFF,t_70#pic_center)
Netscape事件流是事件捕获,从上到下,即从document逐级向下传播到目标元素。我们很少使用事件捕获。
进一步规范
后来ECMAScript在DOM2中对事件进行了进一步的规范:
DOM2级事件规定事件流包括三个阶段:1、事件捕获阶段。2、处于目标阶段。3、事件冒泡阶段。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210623173209660.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzUwMDkzNzg1,size_16,color_FFFFFF,t_70#pic_center)
DOM事件处理
DOM节点中有了事件,就需要进行处理。DOM事件处理分为四个级别:1、DOM0级事件处理。2、DOM1级事件处理。3、DOM2级事件处理。4、DOM3级事件处理。
DOM0级:
具有极好的跨浏览器优势,会以最快速度绑定。
第一种方式:内联模型(行内绑定),将函数名作为HTML标签中属性的属性值。
<div onclick="btnClick()">click</div>
<script>
function btnClick(){
console.log("hello");
}
</script>
第二种方式:脚本模式(动态绑定),通过在JS中选中节点,然后给节点添加onclick属性。这种方式的缺点:同一个节点只能添加一次同类型事件。
<div id="btn">点击</div>
<script>
var btn=document.getElementById("btn");
btn.onclick=function(){
console.log("hello");
}
</script>
DOM0只支持冒泡。
DOM2:
规范之后,有了DOM2级事件处理程序,其中定义了两个方法:
1、addEventListener() ----添加事件侦听器
2、removeEventListener() ----删除事件侦听器
两个方法都有三个参数,1、要处理的事件名。2、作为事件处理程序的函数。3、是一个boolean值,默认为false表示使用冒泡机制,true表示捕获机制。
<div id="btn">点击</div>
<script>
var btn=document.getElementById("btn");
btn.addEventListener("click",hello,false);
btn.addEventListener("click",helloagain,false);
function hello(){
console.log("hello");
}
function helloagain(){
console.log("hello again");
}
</script>
触发目标元素上不区分冒泡还是捕获,按绑定的顺序来执行。
阻止冒泡
有时候我们不需要再继续向上冒泡,可以给其加上stopPropagation函数,阻止程序冒泡。
btn2.addEventListener('click',function(ev){
ev.stopPropagation();
console.log('btn2捕获')
}, true)
事件委托
如果有多个DOM节点需要监听的情况下,给每个DOM绑定监听函数会极大的影响页面性能,因此我们通过事件委托来进行优化,事件委托利用事件冒泡的原理。
不使用事件委托时
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
var li_list = document.getElementsByTagName('li')
for(let index = 0;index<li_list.length;index++){
li_list[index].addEventListener('click', function(ev){
console.log(ev.currentTarget.innerHTML)
})
}
</script>
使用事件委托
var ul_dom = document.getElementsByTagName('ul')
ul_dom[0].addEventListener('click', function(ev){
console.log(ev.target.innerHTML)
})
事件委托的优点:
1、提高性能:每个函数都会占用内存空间只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。
2、动态监听:使用事件委托可以自动绑定动态添加的元素,即新增的节点不需要主动添加也可以一样具有和其他元素一样的事件。
注:学习自知乎:https://zhuanlan.zhihu.com/p/114276880