DOM事件流javascript和html之间的交互是通事件实现的。事件就是文档或者浏览器窗口中发生的一些特定的瞬间。我们可以使用侦听器来预定事件,以便事件发生时执行相应的代码.传统的软件工程中称为观察者模式,使得行为(js)和外观(html和css)松散耦合.
"DOM2级事件"规定事件流包括3个阶段:
- 事件捕获(为截获事件提供了机会)
- 处于目标(实际的目标接收到事件)
- 事件冒泡(可对事件做出响应)
以下面的DOM结构为例:
单击div
元素的时候会按照上述顺序触发事件。
<button onclick="show();">
思考:上述的时间处理程序有什么缺点?
答:缺点有2个。①可能存在时差问题。考虑这样一种情形。show
函数定义在按钮的后面,当DOM还没有加载到script
标签的时候将会发生错误,此种情形可以通过内部添加try-catch
来解决:<button onclick="try{show();}catch(ex){}">
;②拓展事件处理程序的作用链将会是浏览器不兼容的.
DOM0级事件处理程序
该种方式将一个函数赋值给一个事件处理程序的属性,比较简单,兼容性好,例如:
var btn = getElementById('btn')
btn.onclick = function () {
console.log('clicked',this.id); // clicked btn
}
使用DOM0级方法指定的时间处理程序被认为是元素的方法.这个时候的事件处理程序是在元素作用域中运行(this指向当前元素).以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理,删除事件处理程序只需要将事件处理程序的属性设置为null
,例如:btn.onclick = null
.
DOM2级事件处理程序
定义了2个方法addEventListener()
和removeEventListener()
用于指定或者删除事件处理程序.都接收3个参数:事件名,事件处理函数和布尔值(true,捕获阶段调用事件处理函数;false,冒泡阶段调用事件处理函数,缺省为false).这种方式可以弥补了DOM0中不能添加多个事件处理函数的不足:
var btn = getElementById('btn')
btn.addEventListener('click',function(){
console.log(1);
})
btn.addEventListener('click',function(){
console.log(2);
})
// 1 2
以上为btn添加了2个事件处理程序,这2个程序会按照它们的添加它们顺序触发.
IE事件处理程序
IE9之前的版本支持attachEvent()
和detachEvent()
,接收事件名(注意"on")和事件处理函数,只支持在冒泡阶段处理,和DOM0级事件的区别在于attachEvent()
在全局作用域中运行,因此window === this
,attachEvent
也可以绑定多个事件,但是触发的顺序是与添加的时候相反的.
兼容DOM的对象会将一个event
对象传入到事件处理程序中(无论是DOM0还是DOM2),事件处理程序执行完后,event
对象将被销毁;IE中的事件对象是window.event
.在事件处理程序内部this === currentTarget
,而target
则表示的是事件的实际目标,我们来看下面的一个例子:
<body>
<button type="button" id="btn">按钮</button>
<script>
document.body.addEventListener('click',function(e){
console.log(this); // body
console.log(e.currentTarget); // body
console.log(e.target); // button#btn
});
</script>
</body>
事件类型
this
和currentTarget
都是body元素,因为事件是注册到body上的,而target
却是按钮,因为它是事件的真是目标(最具体的元素).由于按钮上并没有注册处理程序,click事件就冒泡到了document.body
并在那里得到处理.(在上面的例子中我们可以使用e.stopProgation()
从而禁止事件传播)其实,恰当使用能力检测就可以写出兼容代码,详见event.js
UI事件
UI事件指的是那些不一定与用户操作有关的事件.
- load:页面完全加载完成后在window上触发;当所有框架内容加载完毕后在框架集上触发;图像加载完成后在
<img>
元素上触发;嵌入内容加载完毕后在<object>
元素上触发 - abort:用户停止下载过程时;如果嵌入的内容没有加载完,则在
<object>
元素上触发 - error:js错误时在window上触发;图像无法加载时在
<img>
上触发;无法加载内容时在<object>
上触发;一个或者多个框架无法加载时在框架集上触发
根据“DOM2 级事件”规范,应该在
document
而非window
上面触发load
事件。但是,所有浏览器都在window
上面实现了该事件,以确保向后兼容,例如我们经常用的window.onload
.
焦点事件
- focus,元素获取焦点时触发.但是该事件不会冒泡.
- blur,元素失去焦点触发,不会冒泡
- focusin,元素获取焦点时触发,与html事件focus等价,但冒泡.
- focusout,元素失去焦点时触发,是html事件blur的通用版本.
当焦点从页面中的一个元素移动到另外一个元素,会依次触发下列事件:
- focusout在失去焦点的元素上触发
- focusin在获得焦点的元素上触发
- blur在失去焦点的元素上触发
- focus在获得焦点的元素上触发
事件委托
添加太多的事件处理程序会带来性能问题(函数是对象,对象就要占内存),解决方案就是采用事件委托.事件委托利用了事件冒泡,只指定一个事件处理程序就可以管理某一类型的所有事件,例如click
事件会一直冒泡到document
,也就是说我们可以为整个页面添加一个onclick事件处理程序而不必为每个元素添加事件处理程序,例如:
<ul id="list">
<li id="li1">li1 content</li>
<li id="li2">li2 content</li>
<li id="li3">li3 content</li>
<li id="li4">li4 content</li>
<li id="li5">li5 content</li>
</ul>
<script>
var list = document.getElementById('list')
list.addEventListener('click',function(ev){
var target = ev.target
console.log(target.id)
switch (target.id) {
//
}
})
</script>