事件一般是用户或者浏览器的某些动作,为响应事件而调用的函数一般称之为事件处理程序,事件处理程序一般是以“on”开头
1. HTML事件处理程序
HTML的事件处理程序都是作为HTML的一种属性,而这些属性必须对应一段可以执行的JS代码
// 第一种处理方式
<input type="button" value="Click Me" onclick="console.log('Clicked')"/>
// 第二种处理方式
<script>
function showMessage() {
console.log("Hello world!");
}
</script>
<input type="button" value="Click Me" onclick="showMessage()"/>
通常事件也会为我们封装一个event对象。而对于this的指向,在上述代码中,this指向的就是元素本身。
需要注意的是在HTML中动态创建包装函数的这种发式,函数的作用域链被扩展了,在这个函数中document和函数本身的成员都可以被当作局部变量访问,具体是通过with方式实现。
function() {
with(document) {
with(this) {
// 属性值
}
}
}
这种方式也说明事件处理程序可以更加方便访问自己的属性(this指向目标元素本身),那么在点击事件时想要获取当前value可以参考如下代码。
<!-- 输出"Click Me" -->
<input type="button" value="Click Me" onclick="console.log(value)">
如果这个input元素位于form元素中时,那么事件处理程序的作用域链还应包含form元素
function() {
with(document) {
with(this.form) {
with(this) {
// 属性值
}
}
}
}
这样的话input可以不需要引用 form元素而直接访问form元素中其他成员
<form method="post">
<input type="text" name="username" value="">
<input type="button" value="Echo Username" onclick="console.log(username.value)">
</form>
HTML指定事件处理程序会存在以下问题:
- HTML在上,事件处理程序在下,那么用户已经点击过按钮,但程序还没被执行。
- 函数的作用域链扩展问题在各个浏览器上表现不同
- JS与HTML强耦合
2. DOM事件处理程序
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<input type="button" value="Click Me" id="mybtn" />
</body>
<script>
let btn = document.getElementById("mybtn");
// 1
btn.onclick = function () {
console.log(this);
};
// 2
btn.addEventListener("click", () => {
console.log(this.id);
}, false);
btn.addEventListener("click", () => {
console.log("Hello world!");
}, false);
// 3
let handler = function () {
console.log(this);
};
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false);
</script>
</html>
通过上述代码我们可以发现,在JS中指定事件处理程序基本分为两步:1、获取元素,2、给元素事件处理程序赋值或添加监听器。
注释1中:所赋函数视为元素的方法,所以该函数的this指向元素,以这种方式添加的事件处理程序是 注册在事件冒泡阶段的。如何移除注册的事件呢?我们可以使用btn.onclick = null的方式。如果事件是在HTML中定义的,即作为HTML属性,以也可使用js中赋值为null的方式来移除事件
注释2中:是属于DOM2 Event中新增的属性,即使用监听器方式。addEventListener:添加事件监听,removeEventListener:移除事件监听。这两个方法暴露在所有DOM元素上,同时他们有三个参数:第一个参数事件名、第二参数事件处理函数、第三个参数一个布尔值。布尔值为true:表示在捕获阶段处理,false:表示在冒泡阶段处理,false为默认值。这种方式可以为元素添加多个事件处理程序,但无法移除事件处理程序
注释3中:与注释2不同点在于它可以移除所添加的事件处理程序。
无论是哪种方式的事件处理程序作用域都在元素,它们不能像HTML方式那种自动扩展作用域。大多数情况下事件处理程序都会被添加到事件冒泡阶段,主要原因是跨浏览器兼容性好。捕获阶段一般适用于拦截操作。
4. IE事件处理程序
IE的实现与DOM类似,但是方法不同,IE使用attachEevent与deleteEvent。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function() {
console.log("Clicked");**
});
attachEvent方法只有两个参数,第一个参数是带有on的。IE的这种方式作用域是全局的,因此this等于window
IE8及早期版本只支持事件冒泡,所以这两个方法也是冒泡阶段的。如果给btn添加两个事件处理程序,执行顺序与添加顺序是反向的,先添加的后执行