【读书笔记】JavaScript 事件

210 阅读4分钟

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

13.1 事件流

事件流描述的是从页面中接收事件的顺序。
  • 13.1.1 事件冒泡

    IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深 的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

<!DOCTYPE html>
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
    <div id="myDiv">Click Me</div>
</body>
</html>

如果你单击了页面中的 <div> 元素,那么这个 click 事件会按照如下顺序传播:
(1)  <div>
(2)  <body>
(3)  <html>
(4)  document

  • 13.1.2 事件捕获

    事件捕获的用意在于在事件到达预定目标之前捕获它。

// 如果仍以前面的 HTML 页面作为演示事件捕获的例子,那么单击 <div>元素就会以下列顺序触发click事件。

(1)  document
(2)  <html>
(3) <body>
(4)  <div>

  • 13.1.3 DOM事件流

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

13.2 事件处理程序

响应某个事件的函数就叫做事件处理程序
  • 13.2.1 HTML事件处理程序

    某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性来指定。

    <input type="button" value="Click Me" onclick="alert('Clicked')" />
    
  • 13.2.2 DOM0 级事件处理程序

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

    var btn = document.getElementById("myBtn");
    btn.onclick = function(){
        alert("Clicked");
    };
    
  • 13.2.3 DOM2 级事件处理程序

    “DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener() 。

    var btn = document.getElementById("myBtn");
    btn.addEventListener("click", function(){
        alert("Hello world!");
    }, false);
    btn.removeEventListener("click", function(){ 
        alert("Hello world!");
    }, false);
    
  • 13.2.4 IE事件处理程序

    IE 实现了与 DOM 中类似的两个方法: attachEvent() 和 detachEvent() 。

    var btn = document.getElementById("myBtn");
    btn.attachEvent("onclick", function(){
        alert("Clicked");
    });
    
    btn.detachEvent("onclick", function(){
        alert("Clicked");
    });
    
  • 13.2.5 跨浏览器的事件处理程序

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

13.3 事件对象

在触发 DOM 上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件有关的信息。
  • 13.3.1 DOM中的事件对象

    兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中。

    var btn = document.getElementById("myBtn");
    btn.onclick = function(event){
        alert(event.type); //"click"
    };
    btn.addEventListener("click", function(event){
        alert(event.type); //"click"
    }, false);
    

  • 13.3.2 IE中的事件对象

    与访问 DOM 中的 event 对象不同,要访问 IE 中的 event 对象有几种不同的方式,取决于指定事 件处理程序的方法。

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert("Clicked");
    window.event.cancelBubble = true;
};
document.body.onclick = function(){
    alert("Body clicked");
}; 
  • 13.3.3 跨浏览器的事件对象
var EventUtil = {
    addHandler: function(element, type, handler){
    //省略的代码
    },
    getEvent: function(event){
        return event ? event : window.event;
    },
    getTarget: function(event){
        return event.target || event.srcElement;
    },
    preventDefault: function(event){
        if (event.preventDefault){
                event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    removeHandler: function(element, type, handler){
    //省略的代码
    },
    stopPropagation: function(event){
        if (event.stopPropagation){
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
};

13.4 事件类型

DOM3级事件”规定了以下几类事件。

13.5 内存和性能

  • 13.5.1 事件委托

    事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

    <ul id="myLinks">
        <li id="goSomewhere">Go somewhere</li>
        <li id="doSomething">Do something</li>
        <li id="sayHi">Say hi</li>
    </ul>
    
    var list = document.getElementById("myLinks");
    EventUtil.addHandler(list, "click", function(event){
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
        switch(target.id){
        case "doSomething":
            document.title = "I changed the document's title";
            break;
        case "goSomewhere":
            location.href = "http://www.wrox.com";
            break;
        case "sayHi":
            alert("hi");
            break;
        }
    });
    

13.7 小结

事件是将 JavaScript 与网页联系在一起的主要方式。“DOM3 级事件”规范和 HTML5 定义了常见的 大多数事件。即使有规范定义了基本事件,但很多浏览器仍然在规范之外实现了自己的专有事件,从而 为开发人员提供更多掌握用户交互的手段。有些专有事件与特定设备关联,例如移动 Safari 中的 orientationchange 事件就是特定关联 iOS 设备的。

在使用事件时,需要考虑如下一些内存与性能方面的问题。
 有必要限制一个页面中事件处理程序的数量,数量太多会导致占用大量内存,而且也会让用户 感觉页面反应不够灵敏。
 建立在事件冒泡机制之上的事件委托技术,可以有效地减少事件处理程序的数量。
 建议在浏览器卸载页面之前移除页面中的所有事件处理程序。

可以使用 JavaScript 在浏览器中模拟事件。“DOM2 级事件”和“DOM3 级事件”规范规定了模拟事 件的方法,为模拟各种有定义的事件提供了方便。此外,通过组合使用一些技术,还可以在某种程度上 模拟键盘事件。IE8及之前版本同样支持事件模拟,只不过模拟的过程有些差异。

事件是 JavaScript中最重要的主题之一,深入理解事件的工作机制以及它们对性能的影响至关重要。