JavaScript面试考点之事件代理
事件代理(Event Delegation),又称之为事件委托。是JavaScript中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown......)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。
事件流是一个事件沿着特定数据结构传播的过程。冒泡和捕获是事件流在DOM中两种不同的传播方法。
DOM事件流(event flow )存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。
事件捕获(event capturing):通俗的理解就是,当鼠标点击或者触发dom事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。自顶向下。
事件冒泡(dubbed bubbling):与事件捕获恰恰相反,事件冒泡顺序是由内到外进行事件传播,直到根节点。自底向上。
addEventListener(event, listener, useCapture)
event---(事件名称,如click,不带on),listener---事件监听函数,useCapture---决定了注册的事件是捕获事件还是冒泡事件,也就是是否采用事件捕获进行事件捕捉,默认为false,即采用事件冒泡方式。
![](https://img.haomeiwen.com/i20308335/998bef5b25f2e87a.png)
![](https://img.haomeiwen.com/i20308335/3d39cbefd691b6b7.png)
Dom需要有事件处理程序,我们都会直接给它设事件处理程序就好了,所以我们需要在每个li都有相同的click点击事件,在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与Dom节点进行交互,访问Dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,就会将所有的操作放到JS程序里面,与Dom的操作就只需要交互一次,这样就能大大的减少与Dom的交互次数,提高性能;
![](https://img.haomeiwen.com/i20308335/09d41cf08e56f812.png)
我们用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果一样。Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的Dom,但是不是真正操作Dom。
事件委托的优点
1)可以大量节省内存占用,减少事件注册
2)可以实现当新增子对象时无需再次对其绑定(动态绑定事件)
JS中阻止冒泡和取消默认事件
1)防止冒泡和捕获
w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true
使用event.stopPropagation()起到阻止捕获和冒泡阶段中当前事件的进一步传播。stopPropagation也是事件对象(Event)的一个方法,作用是阻止目标元素的冒泡事件,但是会不阻止默认行为。
如在一个按钮是绑定一个”click”事件,那么”click”事件会依次在它的父级元素中被触发 。stopPropagation就是阻止目标元素的事件冒泡到父级元素。
2)取消默认事件
w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false;
reventDefault它是事件对象(Event)的一个方法,作用是取消一个目标元素的默认行为。既然是说默认行为,当然是元素必须有默认行为才能被取消,如果元素本身就没有默认行为,调用当然就无效了。
什么元素有默认行为呢?如链接<a>,提交按钮<input type=”submit”>等。当Event 对象的 cancelable为false时,表示没有默认行为,这时即使有默认行为,调用preventDefault也是不会起作用的。
Javascript的return false只会阻止默认行为,而是用jQuery的话则既阻止默认行为又防止对象冒泡。
2、onclick与addEventListener绑定事件的区别
1)onclick事件在同一时间只能指向唯一对象。
2)addEventListener给一个事件注册多个listener。