事 件

概述

  • JavaScript 与 HTML 之间的交互是通过事件实现的
  • 事件就是文档或浏览器窗口中发生的一些特定的交互瞬间

事件流(事件传播)

  • 事件流描述的是从页面中接收事件的顺序
    • 在单击按钮的同时,你也单击了按钮的容器元素,甚至也单击了整个页面
    • 分类
      • IE 的事件流是事件冒泡流
      • Netscape 的事件流是事件捕获流
  • 事件冒泡(event bubbling)
    • IE 的事件流叫做事件冒泡,即事件开始时由最具体的元素(可以认为是你点击的那个元素)接收,然后沿 DOM 树逐级向上传播,在每一级节点上都会发生,直到较为不具体的节点(文档)
  • 事件捕获(event capturing)
    • 事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件
    • 由于老版本的浏览器不支持,因此很少有人使用事件捕获
  • DOM 事件流
    • “DOM2 级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段

事件处理程序

  • 响应某个事件的函数就叫做事件处理程序(或事件侦听器),事件处理程序的名字以”on”开头
  • HTML 事件处理程序
    • 用法

      • showMessage 在其他地方定义
    • 使用这种方法时,on- 属性的值是将会执行的代码,而不是一个函数
    • this 值等于事件的目标元素
  • DOM0 级事件处理程序

    • 每个元素(包括 window 和 document)都有自己的事件处理程序属性,这些属性通常全部小写

      1
      2
      3
      4
      5
      var btn = document.getElementById("myBtn");
      btn.onclick = function() {
      alert("Clicked");
      alert(this.id);
      };
    • 程序中的 this 引用当前元素

    • 同一个事件只能定义一个监听函数,也就是说,如果定义两次 onclick 属性,后一次定义会覆盖前一次
    • 删除通过 DOM0 级方法指定的事件处理程序只要将事件处理程序属性的值设置为 null 即可
  • DOM2 级事件处理程序
    • 定义了两个方法,用于处理指定和删除事件处理程序的操作: addEventListener() 和 removeEventListener()
    • 接受 3 个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是 true,表示在捕获阶段调用事件处理程序;如果是 false,表示在冒泡阶段调用事件处理程序,默认为 false
    • 程序中的 this 引用当前元素
    • 使用 DOM2 级方法添加事件处理程序的主要好处是可以添加多个事件处理程序,会按照添加它们的顺序触发。如果为同一个事件多次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除
    • 通过 addEventListener() 添加的匿名函数将无法移除
  • IE 事件处理程序
    • IE 实现了与 DOM 中类似的两个方法: attachEvent() 和 detachEvent()
    • 这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数
    • 由于 IE8 及更早版本只支持事件冒泡,所以通过 attachEvent() 添加的事件处理程序都会被添加到冒泡阶段
    • attachEvent() 的第一个参数是”onclick”
    • 在使用 attachEvent() 方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window
    • 与 addEventListener()类似,attachEvent()方法也可以用来为一个元素添加多个事件处理程序。不过,与 DOM 方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发
    • 使用 attachEvent 添加的匿名函数将不能被移除
  • 跨浏览器的事件处理程序
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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;
    }
    }
    };

事件对象

  • 在触发 DOM 上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息
  • DOM 中的事件对象
    • 无论指定事件处理程序时使用什么方法(DOM0 级或 DOM2 级),都会传入 event 对象
    • 只有在事件处理程序执行期间, event 对象才会存在;一旦事件处理程序执行完成, event 对象就会被销毁
    • 常见属性
      • event.bubbles
        • bubbles 属性返回一个布尔值,表示当前事件是否会冒泡
      • event.eventPhase
        • 用来确定事件当前正位于事件流的哪个阶段
        • 在捕获阶段 eventPhase 等于 1
        • 处于目标对象上 eventPhase 等于 2
        • 冒泡阶段 eventPhase 等于 3
      • event.currentTarget,event.target
        • currentTarget 属性返回事件当前所在的节点,即正在执行的监听函数所绑定的那个节点。在事件处理程序内部,对象 this 始终等于 currentTarget 的值(就是当前这个元素)
        • target 属性返回事件发生的节点
      • event.type
        • 返回一个字符串,表示事件类型
      • event.preventDefault
        • 阻止特定事件的默认行为,
        • 比如链接的默认行为就是在被单击时会导航到其 href 特性指定的 URL
      • event.stopPropagation
        • 用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡
      • event.stopImmediatePropagation
        • 阻止同一个事件的其他监听函数被调用
  • IE 中的事件对象

    • 在使用 DOM0 级方法添加事件处理程序时, event 对象作为 window 对象的一个属性存在

      1
      2
      3
      4
      5
      var btn = document.getElementById("myBtn");
      btn.onclick = function() {
      var event = window.event;
      alert(event.type); // "click"
      };
    • 如果事件处理程序是使用 attachEvent() 添加的,那么就会有一个 event 对象作为参数被传入事件处理程序函数中

    • returnValue 属性相当于 DOM 中的 preventDefault() 方法,它们的作用都是取消给定事件的默认行为
    • cancelBubble 属性与 DOM 中的 stopPropagation() 方法作用相同,都是用来停止事件冒泡的

事件委托(事件代理)

  • 由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在 DOM 树中尽量最高的层次上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)
    • 整个页面占用的内存空间更少,能够提升整体性能。
  • 可以考虑为 document 对象添加一个事件处理程序,用以处理页面上发生的某种特定类型的事件
  • 如果希望事件到某个节点为止,不再传播,可以使用事件对象的 stopPropagation 方法

移除事件处理程序

  • 添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能
  • 每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的 JavaScript 代码之间就会建立一个连接。这种连接越多,页面执行起来就越慢。如前所述,可以采用事件委托技术,限制建立的连接数量。另外,在不需要的时候移除事件处理程序,也是解决这个问题的一种方案
  • 如果带有事件处理程序的元素被 innerHTML 删除了,那么原来添加到元素中的事件处理程序极有可能无法被当作垃圾回收
    • 如果你知道某个元素即将被移除,那么最好手工移除事件处理程序
  • 页面被卸载之前没有清理干净事件处理程序
    • onunload 事件处理程序移除所有事件处理程序