事件处理程序

事件处理程序:响应某个事件的函数就叫做事件处理程序(或事件侦听器)

HTML事件处理程序

某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性
来指定。这个特性的值应该是能够执行的JavaScript代码。

举例:
要在按钮被点击时执行一些JavaScript,可以像下面这样编写代码

<input type="button" value="点击这里" onclick="alert('Clicked')"/>

当点击这个按钮时,就会显示一个警示框,这个操作是通过指定 onclick 特性并将一些JavaScript 代码作为它的值来定义的。

在HTML中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的脚本,例如下面的例子:

<script type="text/javascript">
	function showMessage() {
		alert("Hello world!")
	}
</script>
<input type="button" value="点击这里" onclick="showMessage()"/>

在这个例子中,点击按钮就会调用 showMessage() 函数。这个函数是在一个独立的script元素中定义的,当然也可以被包含在一个外部文件中。事件处理程序中的代码在执行时,有权访问全集作用域中的任何代码。

HTML中指定事件处理程序的缺点: 存在时差问题;因为用户可能会在HTML元素一出现就在页面上触发相应的事件,但当时的事件处理程序有可能尚不具备执行条件。以上面的例子来说明,假设showMessage() 函数是在按钮下方、也免得最底部定义的。如果用户在页面解析showMessage() 函数之前就点击了,便会引发错误。所以script代码最好是放在html之前。

DOM0级事件处理程序

通过JavaScript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。
每个元素(包括window和document)都有自己的事件处理程序属性,这些属性通常全部小写,例如onclick。
将这种属性的值设置为一个函数,就可以指定事件处理程序,如下所示:
let btn = document.getElementById("myBtn")
btn.onclick = function() {
	 alert("clicked")
}

在此,我们通过文档对象取得了一个按钮的引用,然后为它指定了 onclick 事件处理程序。但要注意,在这些代码运行以前不会指定事件处理程序,因此如果这些代码在页面中位于按钮后面,就有可能在一段事件内怎么点击都没有反应。
使用DOM0级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序中的 this 引用当前元素。来看一个例子:

let btn = document.getElementById("myBtn")
btn.onclick = function() {
	alert(this.id)  // myBtn
}

点击按钮显示的是元素的 ID ,这个 ID 是通过 this.id 取得的。不仅仅是ID,实际上可以在事件处理程序中通过 this 访问元素的任何属性和方法。以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。
也可以删除通过DOM0 级方法指定的事件处理程序,只要像下面这样将事件处理程序属性的值设置为null即可;

btn.onclick = null;  // 删除事件处理程序

将事件处理程序设置为 null 之后, 再点击按钮时将不会有任何动作发生。

如果你使用HTML指定事件处理程序,那么onclick属性的值就是一个包含着在同名HTML特性中指定的代码的函数。而将相应的属性设置为 null ,也可以删除以这种方式指定的事件处理程序。

DOM2级事件处理程序

“DOM2级”事件定义了两个方法,用于处理指定和删除事件处理程序的操作: addEventListener和
removeEventListener()。所有的DOM节点中都包含这两种方法,并且它们都接受3个参数:要处理的事件名、
作为事件处理的函数和一个布尔值(布尔值的参数如果为 true, 表示在事件捕获阶段调用事件处理程序;若是
false,表示在冒泡阶段调用事件处理程序)

要在按钮上为click添加事件处理程序,可以使用如下代码:

let btn = document.getElementById("myBtn")
btn.addEventListener("click",function() {
	alert(this.id)
},false)

这段代码为一个按钮添加了onclick 事件处理程序,并且该事件会在冒泡阶段被触发(因为第三个参数为false)。与DOM0级方法一样,这里添加的事件处理程序也是在其依附的元素的作用域中运行。使用DOM2级方法添加事件处理程序的主要好处是可以添加多个事件处理程序;
例子:

let btn = document.getElementById("myBtn")
btn.addEventListener("click", function() {
	alert(this.id)
},false)
btn.addEventListener("click",function() {
	alert("Hello world!")
},false)

这里添加的两个事件处理程序会按照它们添加的顺序触发,因此会先显示 ID,其次会显示 “Hello world!”。
通过addEventListener()添加的事件处理程序只能使用 removeEventListener() 来移除;移除时传入的参数与添加处理程序时使用的参数相同。所以通过 addEventListener() 添加的匿名函数将无法移除。
举例:

let btn = document.getElementById("myBtn")
btn.addEventListener("click", function() {
	alert(this.id)
},false)
...
btn.removeEventListener("click", function() {
	alert(this.id)
},false)

在这个例子中,我们虽然调用了removeEventListener(),看似使用了相同的参数;但实际上,第二个参数与addEventListener()中的完全是不同的两个参数。所以我们需要在外部单独定义一个函数。
举例:

let btn = document.getElementById("myBtn")
let handler = function() {
	alert(this.id)
}
btn.addEventListener("click", handler,false)
...
btn.removeEventListener("click", handler,false)

这样重写就不会出现问题了。

大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。所以不到万不得已,不使用事件捕获,即不将addEventListener中的第三个参数设置为 true。

IE 事件处理程序

IE实现了与DOM中类似的两个方法: attachEvent() 和 detachEvent()。这两个方法接受两个相同的参数:
事件处理程序名称与事件处理函数。由于IE8及更早版本只支持事件冒泡,所以通过attachEvent()添加事件处理
程序都会被添加到冒泡阶段。

要使用attachEvent() 为按钮添加一个事件处理程序,可以使用如下代码:

let btn = document.getElementById("myBtn")
btn.attachEvent("onclick", function(){
	alert("点击")
})

注意,attachEvent() 的第一个参数是“onclick”,而非DOM的addEventListener() 方法中的“click”。

在IE中使用attachEvent() 与使用DOM0级方法的主要区别在于事件处理程序的作用域。在使用DOM0级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this等于window。
举例:

let btn = document.getElementById("myBtn")
btn.attachEvent("onclick",function() {
	alert(this === window) // true
});

如果你需要编写跨浏览器的代码时,一定要注意这点!!!
与addEventListener类似,attachEvent()方法也可以用来为一个元素添加多个事件处理程序。
举例:

let btn = document.getElementById("myBtn")
btn.attachEvent("onclick", function() {
	alert("Clicked")
})
btn.attachEvent("onclick",function() {
	alert("Hello World!")
})

这里会调用两次attachEvent(), 为同一个按钮添加了两个不同的事件处理程序。不过,与DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。点击这个例子中的按钮,会执行 “Hello World”, 然后再执行Clicked。

使用attachEvnet() 添加的事件可以通过detachEvent() 来移除,条件是必须提供相同的参数。
与DOM方法一样,添加匿名函数也将不能被移除。所以要将相同的函数的引用传给detachEvent(),就可以移除相应的事件处理程序。
举例:

let btn = document.getElementById("myBtn")
let handler = function() {
	alert("Clicked")
}
btn.attachEvent("onclick",handler)
...
btn.detachEvent("onclick",handler)

这个例子将保存在变量handler中的函数作为事件处理程序。因此,后面的detachEvent() 可以使用相同的函数来移除事件处理程序。

支持IE事件处理程序的浏览器有 IE 和 Opera。

跨浏览器的事件处理程序

为了以跨浏览器的方式处理事件,处理浏览器之间的差异,自己编写代码其实也不难,只要恰当地使用能力检测
即可;要保证处理事件的代码能在大多数浏览器下一致地运行,只需关注冒泡阶段。

第一个要创建的方法是addHandler(),它的职责是视情况分别使用DOM0级方法、DOM2级方法或IE方法来添加事件。这个方法属于一个名叫EventUtil() 的对象addHandler()方法接受3个参数:要操作的元素、事件名称和事件处理程序函数。
与addHandler() 对应的方法是removeHandler(),它也接受相同的参数。这个方法的职责是移除之前添加的事件处理程序;无论该事件处理程序是采取什么方式添加到元素中的,如果其他方法无效,默认采用DOM0级方法。
举例:

let 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
		}
	}
}

这两个方法首先都会检测传入的元素中是否存在 DOM2 级方法。 如果存在 DOM2 级方法,则使用该方法:传入事件类型、事件处理程序函数和第三个参数false(表示冒泡阶段)。如果存在的是IE的方法,则采取第二种方案。注意,为了在IE8及更早版本中运行,此时的事件类型必须加上“on”前缀。
最后一种就是使用DOM0级方法(在现代浏览器中,应该不会执行这种代码)。此时,我们使用的是方括号语法来将属性名指定为事件处理程序,或者将属性设置为null。可以像下面这样使用EventUtil对象。
举例:

let btn = document.getElementById("myBtn")
let handler = function() {
	alert("Clicked")
}
EventUtil.addHandler(btn,"click",handler)
...
EventUtil.removeHandler(btn,"click",handler)

addHandler() 和 removeHandler() 没有考虑到所有浏览器的问题,例如在IE中的作用域问题。不过,使用它们添加和移除事件处理程序还是足够了。此外还要注意,DOM0级对每个事件只支持一个事件处理程序。不过好在,只支持DOM0级的浏览器已经没有那么多了,因此这对你而言应该不是什么问题了。

总结:
HTML事件处理程序:是在标签内添加onclick事件,在执行事件代码时,有权访问全局作用域的任何代码;
DOM0级事件处理程序:将某个元素的事件处理程序属性(也就是元素的事件,例如onclick)的值设置为一个函数,当触发那个事件时,就可以执行这个属性的函数。若要移除这个事件处理程序,将这个事件处理程序设置为null; 事件的作用域是当前的元素的作用域;
DOM2级事件处理程序:通过addEventListener()和removeEventListener() 为元素添加事件与移除事件;一共三个参数,第三个参数为true时为事件捕获,为false时为事件冒泡;事件的作用域也是当前元素的作用域;removeEventListener中的参数必须和addEventListener的参数完全相同才能起作用,且事件处理程序必须是从外界引入,不能是匿名函数;
IE事件处理程序:通过attachEvent()与detachEvent() 为元素添加与移除事件,该方法只有两个参数,由于IE8及更早版本只支持事件冒泡,所以默认添加到冒泡阶段;作用域是指向window而不是元素自身;同样匿名函数也不可以被移除。

本文参考于《JavaScript高级程序设计》第三版

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

折木泛舟

我干了,你们随意。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值