DOM事件模型
2017-08-28
一、事件与事件流
事件是与浏览器或文档交互的瞬间,如点击按钮,填写表格等,它是JS与HTML之间交互的桥梁。
DOM是树形结构,如果同时给父子节点都绑定事件时,当触发子节点的时候,这两个事件的发生顺序如何决定?这就涉及到事件流的概念,它描述的是页面中接受事件的顺序。
事件流描述的是从页面中接收事件的顺序。
IE的事件流是事件冒泡:事件开始时由具体元素接收,然后逐级向上传播直到document对象:即 div——body——html——document;
IE9+/现代浏览器支持事件捕获:由document对象先接收到事件,然后沿DOM树依次向下一直传播到事件的实际目标:即 document——html——body——div;
DOM事件流规定的三个阶段:事件捕获阶段,处于目标阶段,事件冒泡阶段。
从DOM事件流模型可以看出,捕获阶段的事件处理函数,一定比冒泡阶段的事件处理函数先执行。
二、事件处理程序
DOM0级事件处理程序
● 写在html标签内,缺点:不好维护
● 将一个函数赋值给一个事件处理属性
例:btn.onClick = function() {}
删除DOM0事件处理程序,只要将对应事件属性置为null即可。
btn.onclick = null;
DOM2级事件处理程序
DOM2级事件定义了两个方法:addEventListener()和removeEventListener()。
接收三个参数:type、handler、useCapture
useCapture=false意味着:将事件处理函数加入到冒泡阶段,在冒泡阶段被调用
useCapture=true意味着:将事件处理函数加入到捕获阶段,在捕获阶段被调用
同一个事件处理函数可以绑定2次,一次用于事件捕获,一次用于事件冒泡。
IE下(DOM2)事件处理程序
attachEvent()添加事件 detachEvent()删除事件
接收相同的两个参数:’on‘ + type 、handler
IE8级更早版本只支持冒泡型事件,所以attachEvent添加的事件都会被添加到冒泡阶段。
IE下使用attachEvent()绑定事件时,事件处理函数中的this指的是window对象。
跨浏览器的事件处理程序
跨浏览器的事件处理函数:
1 | var eventUtil = { |
DOM0和DOM2事件的区别
- DOM0中事件一旦发生就直接调用事件句柄,无传播过程。在DOM2中有一个事件的传播过程。包括事件捕获,目标元素的事件处理程序运行,事件冒泡。
- 一个DOM对象注册多个类型相同的事件时,DOM0级中会发生事件的覆盖,而DOM2级中则会依次执行各个事件函数。
事件处理函数的执行顺序:
捕获阶段的处理函数最先执行,其次是目标阶段的处理函数,最后是冒泡阶段的处理函数。目标阶段的处理函数,先注册的先执行,后注册的后执行。
当用户通过鼠标操作触发 click 事件时,基本的事件触发流程为:
MouseDown 事件 –>( ie下Focus事件)–> MouseUp 事件 –> Click 事件。
若被点击的元素可以获得焦点,并且当前还没有获得焦点时,会在 MouseDown 事件之后默认触发 Focus 事件,再依次触发其后的 MouseUp 和 Click 事件。
非 IE 浏览器中,此情况下元素无法获得焦点,也不会触发 Focus 事件。
三、事件对象
DOM中的事件对象属性
○ type: 获取事件类型
○ target:事件目标
○ stopPropagation() 阻止事件传播(冒泡+捕获)
○ preventDefault() 阻止事件的默认行为
IE中的事件对象属性
○ type: 获取事件类型
○ srcElement:事件目标
○ cancelBubble=true 阻止事件冒泡
○ returnValue=false 阻止事件的默认行为
IE8以及以前可以通过 window.event.cancelBubble=true阻止事件的冒泡;
IE9+/FF/Chrome通过event.stopPropagation()阻止事件的继续传播(冒泡或捕获都支持)。
四、事件委托
事件委托利用了事件冒泡,只用一个事件处理程序就可以管理某一类型的所有事件。
使用场景:
- 给许多子元素绑定相同的事件,比如ul的li元素,或者table的td元素。可以大量节省内存,减少事件注册。
- 可以实现当新增子对象时无需再次绑定事件,对于动态内容极其合适。
优点:
- document对象很快就可以访问,而且可以在页面周期的任何时段为它添加事件处理程序。只要可单击的元素呈现在页面上,就可以立即具备适当的功能。
- 在页面中设置事件处理程序所需的时间更少。只添加一个事件处理程序所需的DOM引用更少,所花时间也更少。
- 整个页面占用内存空间更少,能够提升整体性能。
缺点:
如果把所有事件都用事件代理,可能会出现本不该被触发的事件被绑定上了事件的情况。