JavaScript基础之事件冒泡、事件捕获、事件委托、事件绑定可以说是JavaScript基础中最为重要的知识点。下面就来介绍一下相关知识。
我们知道,在dom模型中,html是多层次的,当一个html元素上产生事件时,该事件会在dom树元素节点之间按照特定的顺序去传播。传播路径的每一个节点,都会收到这个事件,这就是dom事件流。当事件发生后,就会从内向外逐级传播,因为事件流本身没有处理事件的能力,所以,处理事件的函数并不会绑定在该事件源上。例如我们点击了一个按钮,产生了一个click事件,click事件就会开始向上传播,一直到到处理这个事件的代码中。
dom的事件标准定义了俩种事件流:事件冒泡和事件捕获,dom的事件处理流程分为三个阶段,事件捕获,目标事件,事件冒泡。
事件捕获:事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)。
事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。
事件冒泡:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发,当一个元素接收到事件的时候会把他接收到的事件传给自己的父级,一直到window 。
阻止事件冒泡:event.stopPropagation( )和return false
事件捕获和事件冒泡属于两个相反的过程。
事件委托(事件代理):事件委托又叫事件代理,事件委托就是利用事件冒泡,只制定一个时间处理程序,就可以管理某一类型的所有事件。
为什么要事件委托(事件代理):在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的操作dom,那么引起浏览器重绘和回流的可能也就越多,页面交互的事件也就变的越长,这也就是为什么要减少dom操作的原因。每一个事件处理函数,都是一个对象,那么多一个事件处理函数,内存中就会被多占用一部分空间。如果要用事件委托,就会将所有的操作放到js程序里面,只对它的父级(如果只有一个父级)这一个对象进行操作,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能;
事件委托(事件代理)原理:事件委托(事件代理)主要是利用了事件冒泡,事件从最深的节点开始,然后逐步向上传播事件,最终将事件委托给其父级。
事件委托(事件代理)的有点:
- 管理的函数变少了。不需要为每个元素都添加监听函数。对于同一个父节点下面类似的子元素,可以通过委托给父元素的监听函数来处理事件。
- 可以方便地动态添加和修改元素,不需要因为元素的改动而修改事件绑定。
- JavaScript和DOM节点之间的关联变少了,这样也就减少了因循环引用而带来的内存泄漏发生的概率。
适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。(所有用到按钮的事件,多数的鼠标事件和键盘事件) 值得注意的是,mouseover和mouseout虽然也有事件冒泡,但是处理它们的时候需要特别的注意,因为需要经常计算它们的位置,处理起来不太容易。 不适合的就有很多了,举个例子,mousemove,每次都要计算它的位置,非常不好把控,在不如说focus,blur之类的,本身就没用冒泡的特性,自然就不能用事件委托了。
事件绑定:就是操作dom的方式,主要有以下方式:
(1)直接在dom元素上绑定
<input id="btn1" type="button" onclick="test();" />
(2) 用on绑定:同一个 dom 元素上,on 只能绑定一个同类型事件,后者会覆盖前者,不同类型的事件可以绑定多个。
document.body.onClick = () => {
console.log('我是一个绑定在body的事件')
}
document.body.onClick = null
(3)用 addEventListener、attachEvent 绑定:同一个 dom 元素上,用 addEventListener、attachEvent 可以绑定多个同类型事件。addEventListener 事件执行顺序按照事件绑定的先后顺序执行;attachEvent 事件执行顺序则是随机的。
// 绑定
document.body.addEventListener('click', bodyClick, false);
// 解绑
document.body.removeEventListener('click', bodyClick, false);
注意:removeEventListener 第二个参数要和 addEventListener 指向同一个函数才能解绑成功。
addEventListener 的第三个参数若为 false,函数在冒泡阶段执行;若为 true,函数在捕获阶段执行。默认为 false。
最后上一道面试题:在body中添加十个div标签,点击每个div弹出相应的内容
for (let i = 1; i <= 10; i++) {
let div = document.createElement('div')
div.innerHTML = i + '<br>'
document.body.appendChild(a)
div.addEventListener('click', function(e) {
e.preventDefault()
alert(i)
})
}
以上就是JavaScript基础之事件冒泡、事件捕获、事件委托(事件代理)、事件绑定的内容。