# DOM 事件

# 事件

事件:就是用户或浏览器自身执行的某种动作。如:click、load 和 mouseover。

# 事件处理程序

事件处理程序(事件侦听器):是响应某个事件的函数。如:onclick、onload。

# 事件流

事件流:描述的是从页面中接收事件的顺序。

# 事件冒泡

事件冒泡:IE 的事件流叫做事件冒泡。事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档)。

# 事件捕获

事件捕获:Netscape 提出的另一种事件流叫事件捕获。由不太具体的节点先接收到事件,最具体的节点最后接收到事件。

# DOM 事件流

DOM事件流:“DOM2 级事件”规定的事件流包含三个阶段。事件捕获阶段、处于目标阶段和事件冒泡阶段。

多数浏览器都实现了“DOM2 级事件”规范的事件流。但 IE9、Safari、Chrome、Firefox 和 Opera 9.5 及更高版本都会在捕获阶段触发事件对象上的事件。结果,就是有两个机会在目标对象上面操作事件。

# 指定事件处理程序

为事件指定处理程序的方式有:

  • HTML事件处理程序
  • DOM0级事件处理程序
  • DOM2级事件处理程序
  • IE事件处理程序
  • 跨浏览器的事件处理程序

# HTML 事件处理程序

HTML事件处理程序:是在 HTML 标签内为与事件处理程序同名的特性(属性)指定的处理程序。这个处理程序可以是在行内直接执行的 JavaScript 代码,也可以调用在页面其他地方定义的脚本(代码)。

<!-- 行内代码 -->
<input type="button" value="Click Me" onclick="alert('Clicked')" />
<!-- 调用函数 -->
<script type="text/javascript">
  function showMessage() {
    alert('Hello World!');
  }
</script>
<input type="button" value="Click Me" onclick="showMessage()" />
<!-- 删除事件处理程序可以通过指定相应的事件属性为null -->

# DOM0 级事件处理程序

DOM0级事件处理程序是指,先取得一个要操作的对象的引用,将一个函数赋值给他的事件处理程序属性。以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。DOM0 级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序中的 this 引用当前元素。例子:

// 要使用js指定事件处理程序,首先必须取得一个要操作的对象的引用
var btn = document.getElementById('myBtn');
btn.onclick = function() {
  alert(this.id); // "myBnt"
};
btn.onclick = null; // 删除事件处理程序

# DOM2 级事件处理程序

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

var btn = document.getElementById("myBtn");
btn.addEventListener("click",function(){
    // 与DOM0级方法一样,这里添加的事件处理程序也是在其依附的元素的
    // 作用域中运行
    alert(this.id);
}, false);
// DOM2级方法添加事件处理程序的主要好处是可以添加多个事件处理程序。
// 会按添加的顺序被触发
btn.addEventListener("click",function(){
    alert("Hello World!");
}, false);
// 通过addEventListene()添加的事件处理程序只能用
// removeEventListener()来移除.所以添加的匿名函数将无法移除。
btn.removeEventListener("click",function(){ // 没有用!
    alert(this.id);
}, false);

var handler = function(){
    alert(this.id);
};
btn.addEventListener("click",handler,false);
btn.removeEventListener("click",handler,false); // 有效!

大多数情况下,都是将事件处理程序添加到冒泡阶段,这样可以最大限度地兼容各种浏览器。不是特别需要不建议在事件捕获阶段注册事件处理程序。

# IE 事件处理程序

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

var btn = document.getElememtById('myBtn');
// 注意第一个参数是“onclick”,而 DOM 的 addEventListener()是“click”
btn.attachEvent('onclick', function() {
  alert('Clicked');
});
// attachEvent()与 DOM0 级方法的主要区别在于,事件处理程序的作用域。
// DOM0 级方法,事件处理程序会在其所属元素的作用域内运行;
// 用 attachEvent(),事件处理程序会在全局作用域中运行,this 等于 window
btn.attachEvent('onclick', function() {
  alert(this === window); // true
});
// 与 addEventListener()类似,attachEvent()可以添加多个事件处理程序
// 区别是,执行顺序是与添加顺序相反的,最后添加的先执行。
// 上面代码会先显示 true,然后显示 Click

// 与 addEventListener()一样,添加的匿名函数无法移除
btn.detachEvent('onclick', function() {
  // 无效!
  alert('Click');
});
var handler = function() {
  alert('Click');
};
btn.attachEvent('onclick', handler);
btn.detachEvent('onclick', handler); // 有效!

# 跨浏览器的事件处理程序

  • 跨浏览器的事件处理程序,就是自定义的方法,兼容不同浏览器对处理事件程序的差别。
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;
    }
  }
};

// 调用示例
var btn = document.getElementById('myBtn');
var handler = function() {
  alert('Clicked');
};
EventUtil.addHandler(btn, 'click', handler);
//这里省略了其他代码
EventUtil.removeHandler(btn, 'click', handler);

# 阻止事件传播和默认事件

阻止事件流的传播和阻止事件的默认行为都需要利用事件对象,即 event 对象。

  • prevnetDefault():阻止特定事件的默认行为。只有(事件对象的)cancelable 属性设置为 true 的事件,才可以使用 preventDefault()来取消默认事件。
  • stopPropagation():用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡。