事件:
事件就是文档或者浏览器窗口发生的一些特定交互的瞬间。 js与html之间的交互是通过事件实现的。
#事件流:
假如浏览器窗口上有一组的同心圆,当你单击圆心时,其实你也单击了窗口上所有的圆。换句话说,在单击按钮的同时,其实也单击了按钮的容器元素,甚至单击了整个页面。那页面中接收这个单击事件的顺序又是怎样的呢。 事件流就是描述从页面接收事件的顺序。
在最初IE与其他开发团队提出了完全相反的事件流概念。 IE的事件流是事件冒泡流,而其他团队则是事件捕获流。
事件冒泡和事件捕获的流程可以查看这个link
HTML事件处理程序:
事件处理程序中的代码在执行时,有权访问全局作用域的任何代码。事件处理程序中会创建一个封装着元素属性值的函数这个函数可以像访问局部变量一样访问document及该元素本身。这个函数的有个局部变量event,这个变量可以直接访问事件对象.
<input type="button" value="click" onclick="alert(event.type)"> //click
<input type="button" value="click" onclick="alert(this.value)"> //click this的值等于目标元素
<input type="button" value="click" onclick="alert(value)">
//因为事件处理程序所创建的函数可以访问元素本身。所有可以直接获得value值
缺点:
1、存在一个时间差的问题。用户可能会在html元素一出现在页面上就触发相应的事件,但事件处理程序可能还不具备执行条件。
2、扩展事件处理程序的作用域链在不同的浏览器中会导致不同的结果。
3、html与javascript代码紧密耦合。
DOM0级事件处理程序:这种方式在事件冒泡流阶段被处理。
var btn = document.getElementById("myBtn")
btn.onclick = function() {
alert(this.id)
}
DOM2级事件处理程序:
定义了两个方法:
1、element.addEventListener(event, function, useCapture)
2、element.removeEventListener(event, function, useCapture)
根据上两个方法参数可知,通过addEventListener()添加的匿名函数将无法移除。
IE事件处理程序:
两个方法:
1、attachEvent()
2、detachEvent()
使用attachEvent()与DOM0级的区别就是作用域。DOM0级,事件处理程序会在元素的作用域内运行,attachEvent()事件处理程序则会在全局作用域中运行。
跨浏览器事件处理程序:
1 var EventUtil = {
2
3 addHandler:function (element,type,handler) {
4 if(element.addEventListener){
5 element.addEventListener(type, handler,false);
6 } else if (element.attachEvent) {
7 element.attachEvent("on" + type,handler);
8 }else {
9 element["on" + type] = handler;
10 }
11 },
12
13 removeHandler:function (element,type,handler) {
14 if (element.removeEventListener) {
15 element.removeEventListener(type, handler,false);
16 } else if (element.detachEvent) {
17 element.detachEvent("on" + type,handler);
18 }else {
19 element["on" + type] = null;
20 }
21 }
22 };
事件对象
在触发DOM上的某个事件时,会产生一个事件对象event这个对象包含着所有与事件有关的信息。event对象包含与创建它的特定事件有关的属性和方法。不同的事件类型,有不同的属性和方法,但所有事件都会有下表的成员,只写了常见的,全部属性查看javascript高级教程p355。
属性/方法 | 说明 |
---|---|
bubbles | 表明事件是否冒泡 |
cancelabel | 表明是否可以取消事件的默认行为 |
defaultTarget | 事件处理程序当前正在处理的程序 |
defaultPrevented | 为true时表示已经调用了 preventDefault(DOM3事件新增) |
preventDefault | 取消事件默认行为 |
stopImmediatePropagation | 阻止事件进一步捕获或冒泡(DOM3新增) |
stopPropagation | 阻止事件进一步捕获或冒泡 |
target | 事件的目标 |
type | 被触发的事件类型 |
eventPhase属性可以来确定事件当前正位于事件流哪个阶段。
IE取消事件冒泡需要设置 cancelBubble = true
事件处理程序内部,对象的this
始终等于currentTarget
的值,而target
则只包含事件的实际目标。如果直接将事件处理程序指定给目标元素,则三者相等,如果事件绑定在父元素上,三个值则不一定相等。
事件类型
1、UI事件 2、焦点事件 3、鼠标事件 4、滚轮事件
5、键盘事件 6、文本事件 7、合成事件 8、变动事件
事件委托
在js中,添加到页面的事件处理程序数量直接关系到页面的整体性能。
原因1:所有事件处理程序都是对象,都会占用内存。
原因2:必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。
对于“事件处理程序过多”解决方案事件委托,利用的就是事件冒泡,只指定一个事件处理程序,就可以管理一类型的所有事件。
一个常用例子,这是一个无序列表的DOM结构:
<ul>
<li id="li1">我是第1个li</li>
<li id="li2">我是第2个li</li>
<li id="li3">我是第3个li</li>
</ul>
- 第一种做法:给每个
<li>
添加点击事件,这样能分别处理事件,展示不同的内容。
document.getElementById('li1').addEventListener('click', function(e) {
console.log('我是第一个li')
}, false)
document.getElementById('li2').addEventListener('click', function(e) {
console.log('我是第2个li')
}, false)
document.getElementById('li3').addEventListener('click', function(e) {
console.log('我是第3个li')
}, false)
- 第二种做法:给
<li>
元素的父元素<ul>
添加一个处理事件,
document.querySelector('ul').addEventListener('click', function (e) {
console.log(e.target.innerText)
}, false)
移除事件处理程序
事件指定给元素时,浏览器代码与支持页面交互的js代码之间就会建立一个连接。连接越多,页面执行起来越慢,内存中保存不用的“空事件处理程序”是造成web应用程序内存与性能问题的主要原因。解决方案之一不需要的时候移除事件处理程序。
移除事件处理程序方法:
1、在执行完某个事件后,若知道哪个元素将被移除,最好手工移除事件处理程序。
element.onclick = null
2、页面卸载之前,通过onunload
事件处理程序移除所有处理程序