浏览器事件之事件处理程序
介绍
事件是用户或浏览器自身执行的某种行动(如click、mousemove等)。而处理对应事件的程序称为事件处理程序(或事件监听器)。
html事件处理程序
通过在html标签中设置与相应事件处理程序同名的属性来指定事件处理程序的方法被称之为 HTML事件处理程序。如下面这段代码:
<!DOCTYPE html>
<html>
<head></head>
<body>
<button onclick="alert('click button1')">click1</button>
<button onclick="handleButtonClick()">click2</button>
</body>
<script>
function handleButtonClick() {
alert('click button2');
}
</script>
</html>
在 HTML 中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的脚本。就这个例子来说“click1”按钮就在标签中包含了具体的执行动作。而“click2”按钮的事件处理函数则放在了下方的<script>标签中。
DOM0级事件处理程序
在JavaScript代码中通过将一个函数赋值给一个事件处理程序属性来指定事件处理程序的方法被称之为DOM0级事件处理程序。
在指定事件处理函数前,要先获得一个操作对象的引用,如下面这段代码:
<!DOCTYPE html>
<html>
<head></head>
<body>
<button id="myBtn">click</button>
</body>
<script>
document.getElementById('myBtn').onclick = function(ev) {
alert('click myBtn');
};
</script>
</html>
上方例子中我们通过文档对象取得了一个按钮的引用,然后为它指定了onclick事件处理程序。但要注意,在这些代码运行以前不会指定事件处理程序,因此如果这些代码在页面中位于按钮后面,就有可能在一段时间内怎么单击都没有反应。
使用DOM0级方法指定的事件处理程序被认为是元素的方法。所以在这个时候事件处理函数的作用域是在元素中,也就是说元素中的this是指向的该元素。
<!DOCTYPE html>
<html>
<head></head>
<body>
<button id="myBtn">click</button>
</body>
<script>
var myBtn = document.getElementById('myBtn');
myBtn.onclick = function(ev) {
alert(myBtn.isEqualNode(this)); // true
};
</script>
</html>
不仅能通过DOM0级方法指定事件处理函数,也能通过DOM0级方法删除事件处理程序,只需将事件处理程序属性的值设为null即可:
myBtn.onclick = null;
使用DOM0级事件处理程序存在许多缺点如:
- 存在时差问题。因为用户可能会在HTML元素一出现在页面上就触发相应的事件,但当时的事件处理程序有可能尚不具备执行条件。
- 扩展事件处理程序的作用域链在不同浏览器中会导致不同结果。不同JavaScript引擎遵循的标识符解析规则略有差异,很可能会在访问非限定对象成员时出错。
- HTML与JavaScript代码紧密耦合。如果要更换事 件处理程序,就要改动两个地方:HTML代码和JavaScript代码。
......
DOM2级事件处理程序
DOM2级事件包含了两种方法用于增加和删除事件处理程序,分别为addEventListener()、removeEventListener()。
它们都接受三个参数:
- 事件名,如“click”(注意: 不是“onclick”)
- 事件处理函数
- 是否在捕获阶段调用事件处理程序,如果为true则在捕获阶段调用事件处理程序,否则在冒泡阶段调用事件处理程序
<!DOCTYPE html>
<html>
<head></head>
<body>
<button id="myBtn">click</button>
</body>
<script>
var myBtn = document.getElementById('myBtn');
myBtn.addEventListener(
'click',
function(ev) {
alert(1);
},
false
);
</script>
</html>
上面的代码为一个按钮添加了onclick事件处理程序,而且该事件会在冒泡阶段被触发(因为最后一个参数是false)。与DOM0级方法一样,这里添加的事件处理程序也是在其依附的元素的作用域中运行。使用DOM2级方法添加事件处理程序的主要好处是可以添加多个事件处理程序。看下面的例子:
<!DOCTYPE html>
<html>
<head></head>
<body>
<button id="myBtn">click</button>
</body>
<script>
var myBtn = document.getElementById('myBtn');
myBtn.addEventListener(
'click',
function(ev) {
alert(1);
},
false
);
myBtn.addEventListener(
'click',
function(ev) {
alert(2);
},
false
);
</script>
</html>
这里为按钮指定了两个事件处理程序,运行上面的例子,浏览器会先后弹出1和2。
若想使用removeEventListener()删除事件处理程序,则需先指定要删除的事件名,再指定函数名(注意:若在元素指定事件时是使用的匿名函数,是无法被删除的),最后指定处理阶段。看看下面的例子:
<!DOCTYPE html>
<html>
<head></head>
<body>
<button id="myBtn">click</button>
</body>
<script>
var myBtn = document.getElementById('myBtn');
function handleBtnClick() {
alert(2);
}
// 匿名函数
myBtn.addEventListener(
'click',
function(ev) {
alert(1);
},
false
);
// 具名函数
myBtn.addEventListener('click', handleBtnClick, false);
// 无效
myBtn.removeEventListener(
'click',
function(ev) {
alert(1);
},
false
);
// 有效
myBtn.removeEventListener('click', handleBtnClick, false);
</script>
</html>
大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。最好只在需要在事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段。如果不是特别需要,我们不建议在事件捕获阶段注册事件处理程序。
IE事件处理程序
IE实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。由于IE8及更早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){ alert("Clicked"); });
attachEvent()的第一个参数是"onclick",而非DOM的addEventListener()方法中的"click"。
在IE中使用attachEvent()与使用DOM0级方法的主要区别在于事件处理程序的作用域。在使用DOM0级方法的情况下,事件处理程序会在其所属元素的作用域内运行。在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this等于window。
广州设计公司https://www.houdianzi.com 我的007办公资源网站https://www.wode007.com
跨浏览器的事件处理程序
若想兼容DOM0级事件处理程序、DOM2级事件处理程序以及IE事件处理程序。可使用下面的方法进行封装和调用:
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent('on' + type, handler);
} else {
element['on' + type] = handler;
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent('on' + type, handler);
} else {
element['on' + type] = null;
}
},
};