1. 不同的事件类型

  1. 当浏览网站时,下表中的事件会发生在浏览器中,而这些事件都可以用来触发 JavaScript 代码中的函数。
  2. 当事件发生时,我们通常称之为事件发生或被触发。
  3. 对于事件的处理,我们通常会称之为事件触发了函数或脚本。
事件说明
UI事件当与浏览器 UI 本身(不是网页)交互时发生的事件
loadWeb 页面加载完成
unloadWeb 页面正在卸载(通常因为请求了一个新页面)
error浏览器遇到 JavaScript 错误或有不存在的资源
resize浏览器窗口大小发生了变化
scroll用户使用滚动条移动了页面
键盘事件当用户操作键盘时发生(也叫输入事件)
keydown用户第一次按下一个键(按住这个键时会反复触发)
keyup用户松开了一个键
keypress键入了一个字符(按住这个键时会反复触发)
鼠标事件当用户操作鼠标、触控板或触摸屏时发生
click用户在同一个元素上按下并松开一个按键
dbclick用户在同一个元素上连续两次按下并松开一个按键
mousedown用户在一个元素上按下鼠标按键
mouseup用户在一个元素上松开鼠标按键
mousemove用户移动鼠标(不会发生在触摸屏上)
mouseover用户将鼠标移到一个元素上
mouseout用户将鼠标从一个元素上移开
焦点事件当一个元素得到或失去焦点时发生
focus/focusin元素得到焦点
blur/focusout元素失去焦点
表单事件当用户与表单元素进行交互时发生
input<input><textarea> 元素中的值发生了变化
change复选框、单选框、单选按钮的值发生了变化
submit用户提交表单
reset用户单击了重置按钮
cut用户从一个表单域中剪切了内容
copy用户从一个表单域中复制了内容
paste用户向一个表单域中粘贴了内容
select用户在一个表单域中选中了一些文本
变动事件脚本修改了 DOM 结构后发生
DOMSubtreeModified文档发生了变化
DOMNodeInserted一个节点被插入为另一个节点的直接子节点
DOMNodeRemoved一个节点被从另一个子节点中移除
DOMNodeInsertedIntoDocument一个节点被插入为另一个节点的后代
DOMNodeRemovedFromDocument一个节点被从其祖先节点上移除

2. 事件触发 JavaScript 代码过程

  1. 事件触发 JavaScript 代码的过程分为三个步骤,这些步骤被称为"事件处理"
    1. 选中需要使用脚本进行事件响应的元素节点
    2. 声明需要在选中节点上响应触发的事件,该步骤也被称为将事件绑定到 DOM 节点
    3. 指定当事件发生时需要运行的代码

3. 将事件绑定到元素的三种方法

3.1. HTML 事件处理程序属性(不推荐)

  1. HTML 的一些标签中可能会带有某些属性,该属性对应着各种事件,该属性的值是事件触发时响应的 JS 程序。
1
<a onclick="test()">测试</a>
  1. HTML 事件处理程序中,属性的名称是和事件的名称一致的,不过需要加上前缀 “on”。

3.2. 传统的 DOM 事件处理程序

1
element.onevent = functionName;
  1. 这里 element 是目标 DOM 元素节点,onevent 是绑定到该节点的事件,使用前缀 on,functionName 是需要调用的函数的名称(不需要加小括号)。
  2. 当函数被调用时,函数名后的小括号会通知 JS 解释器立即运行,然而在事件处理中,我们不希望它马上执行,因此需要去掉小括号。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<!DOCTYPE html>
<html>
    <head>
        <title>传统的 DOM 事件处理程序</title>
        <link rel="stylesheet" href="hello.css" type="text/css" />
    </head>
    <body>
        <article>
            <div class = "red">test</div>
        </article>
        <script src = "./hello.js"></script>
    </body>
</html>
1
2
3
4
5
function test() {
    alert("测试");
}
var el = document.getElementsByClassName("red")[0];
el.onclick = test;

3.3. 事件监听器

  1. 事件监听器可以同时触发多个函数。
1
element.addEventListener('event', functionName [, Boolean]);
  1. 其中 element 代表目标 DOM 元素节点,’event’ 代表要监听的事件名称,functionName 代表要调用的函数的名称,[, Boolean] 代表事件流,指定是否为捕获方式的事件响应,通常被设置为 false。

4. 事件流

  1. HTML 元素都位于另一些元素中。
  2. 如果移动鼠标到一个链接上,或者点击一个链接,同样会把鼠标移到它的父级元素上,或者点击它的父级元素。
  3. 事件冒泡:事件从最具体的节点开始向外传播到最宽泛的节点。这是事件流的默认类型。
  4. 事件捕获:事件从最宽泛的节点开始向内传播到最具体的节点。

5. 事件流的意义

  1. 只有当代码在一个元素和其祖先元素或后代元素上都有事件处理程序时,事件流才会变得非常重要。
  2. 对于传统的 DOM 事件处理程序(以及 HTML 事件属性),所有的现代浏览器默认回使用事件冒泡模型而不是事件捕获模型。
  3. 使用事件监听器时,addEventListener() 方法的最后一个参数允许选择事件触发的方向:
    • true 表示捕获方式
    • false 表示冒泡方式

6. 事件对象

  1. 当事件发生时,事件对象会告诉你关于这个事件的信息,以及它发生在哪个元素上,例如:
    • 事件发生在哪个元素上
    • 在键盘事件中按下了哪个键
    • 在点击事件中,用户点击了视图窗口的哪部分
  2. 事件对象会作为参数传递给任何事件处理程序或事件监听器的函数。
  3. 如果需要传递一个参数给命名函数,事件对象会作为匿名封装函数的第一个参数传递进去(自动发生——,然后需要为命名函数指定相应的参数。
  4. 当事件对象被传递给函数时,它的参数名称通常是 e,这是常用缩写。
1
2
3
el.addEventListener('click', function(e) {
    ....
}, false);
  1. 当事件监听器调用函数时,事件对象的引用会自动传递给方法,不需要进行任何额外操作。

7. 事件委托

  1. 为大量的元素创建事件监听器会造成页面速度下降,不过事件流允许你在父元素上监听事件。
  2. 在事件流中,事件可以影响到容器元素,因此,可以将事件处理程序放置在一个容器元素上,然后使用事件对象的 target 属性找到它的后代中是哪一个发生了事件。
  3. 事件委托可以适用于新的元素,因为如果向 DOM 树中添加了新的元素,那么不需要再向这个新元素上添加事件处理程序,因为这个工作已经被委托给一个祖先元素。
  4. 同时,事件委托也可以解决 this 关键字的限制。

8. 改变默认行为

  1. 事件对象有一些方法可以改变一个元素的默认行为,以及它的祖先元素如何对这个事件做出响应。
  2. 有些事件,例如提交表单,会把用户导向另外一个页面。为了阻止这类元素的默认行为,可以使用事件对象的 preventDefault() 方法。
  3. 处理完某个元素上的事件后,可能需要阻止这个事件向其祖先元素继续冒泡传播,可以使用 stopPropagation() 方法。
  4. 也可以直接 return false 来同时实现上面两者,但要注意,它会打断后面程序的执行。

9. 事件发生在哪个元素上

  1. 当调用一个函数时,事件对象的 target 属性用于获得事件发生在哪个元素上的最好方法。
  2. 也可以使用 this 关键字来获取事件发生的元素,this 关键字指向函数的所有者,在下面这种情况下,this 对象指向的是事件的元素:
1
2
3
4
el.addEventListener('click', test, false);
function test() {
    ....
}
  1. 如果需要向函数传递参数,那么 this 关键字将会失效,因为这个函数的所有者不再是事件监听器所绑定的元素,而是那个匿名函数,这里需要把发生了这个事件的元素作为另一个参数传递给元素:
1
2
3
el.addEventListener('click', function() {
    test(2, el)
}, false);