JavaScript 高级程序设计(第13章 事件)

第13章 事件

1. 事件流

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

(1) 事件冒泡

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

(2) 事件捕获

Netscape Communicator 团队提出的另一种事件流叫做事件捕获(event capturing)。事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在 事件到达预定目标之前捕获它。

(4) DOM事件流

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段处于目标阶段事件冒泡阶段。首 先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶 段,可以在这个阶段对事件做出响应。

2. 事件处理程序

事件就是用户或浏览器自身执行的某种动作。诸如 click、load 和 mouseover,都是事件的名字。 而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以"on"开头,因此 click 事件的事件处理程序就是 onclick,load 事件的事件处理程序就是 onload。

(1) HTML事件处理程序

  1. 某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性来指定。这个 特性的值应该是能够执行的 JavaScript 代码。
  2. JavaScript代码不能在其中使用未经转义的 HTML 语法字符, 例如和号(&)、双引号("")、小于号(<)或大于号(>)。
  3. 事件处理程序中的代码在执行时,有权访问全局作用 域中的任何代码。
  4. 会创建一个封装着元素属性值的函数,这个函数中有一个局部变量 event,也就是事件对象,通过 event 变量,可以直接访问事件对象。


  1. 在这个函数内部,this 值等于事件的目标元素。


(2) DOM0 级事件处理程序

var btn = document.getElementById("myBtn");
    btn.onclick = function(){
        alert("Clicked");
    };
  1. 使用 DOM0 级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序中的 this 引用当前元素
var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert(this.id);    //"myBtn"
};
  1. 删除事件处理程序
btn.onclick = null; //删除事件处理程序

(3) DOM2 级事件处理程序

addEventListener() 和 removeEventListener()方法:

  1. 所有 DOM 节点中都包含这两个方法,并且它们都接受3 个参数:要处 理的事件名作为事件处理程序的函数一个布尔值。最后这个布尔值参数如果是 true,表示在捕获 阶段调用事件处理程序;如果是 false,表示在冒泡阶段调用事件处理程序。
  1. 与 DOM0 级方法一样,这里添加的事件处理程序也是在其依附的元素的作用域 中运行。
  2. 使用 DOM2 级方法添加事件处理程序的主要好处是可以添加多个事件处理程序,事件处理程序会按照添加它们的顺序触发
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
    alert(this.id);
}, false);
btn.addEventListener("click", function(){
    alert("Hello world!");
}, false);
  1. 通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()来移除;移 除时传入的参数与添加处理程序时使用的参数相同。这也意味着通过 addEventListener()添加的匿名函数将无法移除

(4) IE事件处理程序

attachEvent()和 detachEvent()方法:

  1. 这两个方法接受相同的两个参数:事件处理程序名称事件处理程序函数
  2. 由于 IE8 及更早版本只支持事件冒泡,所以通过 attachEvent()添加的事件处理程序都会被添加到冒泡阶段
  3. attachEvent()的第一个参数是"onclick",而非 DOM 的 addEventListener()方法中 的"click"。
  4. 使用 attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window。
  5. 事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发

(5) 跨浏览器的事件处理程序

EventUtil 的对象,本书将使用这个对象来处理浏览器间的差异。

  1. 该对象有一个addHandler()方法,它的职责是视情况分别使用 DOM0 级方法、DOM2 级方 法或 IE 方法来添加事件。addHandler()方法接受3 个参数:要操作的元素事件名称事件处理程序函数
  2. removeHandler(),它也接受相同的参数,这个方法的职责是移除之前添加的事件处理程序。
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);

3. 事件对象

在触发 DOM 上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素事件的类型以及其他与特定事件相关的信息

(1) DOM中的事件对象

JavaScript 高级程序设计(第13章 事件)_第1张图片
JavaScript 高级程序设计(第13章 事件)_第2张图片
event对象的属性和方法
  1. 在事件处理程序内部,对象 this 始终等于 currentTarget 的值,而target 则只包含事件的实际目标。如果直接将事件处理程序指定给了目标元素,则 this、currentTarget 和 target 包含相同 的值。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
    alert(event.currentTarget === this);//true
    alert(event.target === this);//true
};
  1. 如果事件处理程序存在于按钮的父节点中(例如 document.body),那么这些值是 不相同的。
document.body.onclick = function(event){ 
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true 
alert(event.target === document.getElementById("myBtn"));//true
};

通过一个函数处理多个事件时,可以使用 type 属性:

var btn = document.getElementById("myBtn");
var handler = function(event){
switch(event.type){
        case "click":
            alert("Clicked");
            break;
        case "mouseover":
            event.target.style.backgroundColor = "red";
            break;
        case "mouseout":
            event.target.style.backgroundColor = "";
            break;
} 
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;

(2) IE中的事件对象

  1. 在使用DOM0 级方法添加事件处理程序时,event 对象作为 window 对象的一个属性存在。
var btn = document.getElementById("myBtn");
    btn.onclick = function(){
        var event = window.event;
        alert(event.type);     //"click"
};
  1. 如果事件处理程序是使用 attachEvent()添加的,那 么就会有一个 event 对象作为参数被传入事件处理程序函数中。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(event){ alert(event.type); //"click"
});
  1. DOM0 级事件处理程序是在元素的作用域中运行,this 引用当前元素,使用 attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window
var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert(window.event.srcElement === this);
};
btn.attachEvent("onclick", function(event){
    alert(event.srcElement === this);
});

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

4. 事件类型

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

(1) UI(User Interface,用户界面)事件,当用户与页面上的元素交互时触发;
(2) 焦点事件,当元素获得或失去焦点时触发;
(3) 鼠标事件,当用户通过鼠标在页面上执行操作时触发;
(4) 滚轮事件,当使用鼠标滚轮(或类似设备)时触发;
(5) 文本事件,当在文档中输入文本时触发;
(6) 键盘事件,当用户通过键盘在页面上执行操作时触发;
(7) 合成事件,当为 IME(Input Method Editor,输入法编辑器)输入字符时触发;
(8) 变动(mutation)事件,当底层 DOM 结构发生变化时触发。
(9) 变动名称事件,当元素或属性名变动时触发。此类事件已经被废弃,没有任何浏览器实现它们,因此本章不做介绍。

(1) UI事件

UI 事件如下:

  1. DOMActivate:表示元素已经被用户操作(通过鼠标或键盘)激活。这个事件在 DOM3 级事 件中被废弃,但 Firefox 2+和 Chrome 支持它。考虑到不同浏览器实现的差异,不建议使用这个 事件。
  2. load:当页面完全加载后在 window 上面触发,当所有框架都加载完毕时在框架集上面触发, 当图像加载完毕时在元素上面触发,或者当嵌入的内容加载完毕时在元素上面 触发。
  3. unload:当页面完全卸载后在 window 上面触发,当所有框架都卸载后在框架集上面触发,或 者当嵌入的内容卸载完毕后在元素上面触发。
  4. abort:在用户停止下载过程时,如果嵌入的内容没有加载完,则在元素上面触发。
  5. error:当发生 JavaScript 错误时在 window 上面触发,当无法加载图像时在元素上面触 发,当无法加载嵌入内容时在元素上面触发,或者当有一或多个框架无法加载时在框
    架集上面触发。第 17 章将继续讨论这个事件。
  6. select:当用户选择文本框()中的一或多个字符时触发。第 14 章将
    继续讨论这个事件。
  7. resize:当窗口或框架的大小变化时在 window 或框架上面触发。
  8. scroll:当用户滚动带滚动条的元素中的内容时,在该元素上面触发。元素中包含所加载页面的滚动条。
  9. 除了 DOMActivate 之外,其他事件在 DOM2 级事件中都归为 HTML 事件(DOMActivate 在 DOM2级中仍然属于 UI 事件)。

    • 确定浏览器是否支持 DOM2 级事件规定的 HTML 事件
    var isSupported = document.implementation.hasFeature("HTMLEvents", "2.0");
    
    • 确定浏览器是否支持“DOM3 级事件”定义的事件
    var isSupported = document.implementation.hasFeature("UIEvent", "3.0");
    
    * load 事件
    1. 当页面完全加载后(包括所有图像、JavaScript 文件、 CSS 文件等外部资源),就会触发 window 上面的 load 事件。

    两种定义 onload 事件处理程序的方式:

    (1) 通过 JavaScript 来指定事件处理程序的方式

    EventUtil.addHandler(window, "load", function(event){
        alert("Loaded!");
    });
    

    》这个 event 对象中不包含有关这个事件的任何附加信息,但在兼容 DOM 的浏览器中,event.target 属性的值会被设置为 document,而 IE 并不会为这个事件设置 srcElement 属性。

    (2) 为元素添加一个 onload 特性

    
        
            
                Load Event Example
            
            
            
    
    
    *unload 事件

    这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生 unload 事件。而利用这个事件最多的情况是清除引用,以避免内存泄漏。

    两种指定 onunload 事件处理程序的方式:

    (1) 第一种方式是使用 JavaScript。

    EventUtil.addHandler(window, "unload", function(event){
            alert("Unloaded");
    });
    

    》 此时生成的 event 对象在兼容 DOM 的浏览器中只包含 target 属性(值为 document)。IE8 及之 前版本则为这个事件对象提供了 srcElement 属性

    (2) 为元素添加一个特性。

    
    
    
        Unload Event Example
    
    
    
    
    
    * resize 事件

    当浏览器窗口被调整到一个新的高度或宽度时,就会触发 resize 事件。

    1. 这个事件在 window(窗 口)上面触发,因此可以通过 JavaScript 或者元素中的 onresize 特性来指定事件处理程序。
    2. 在兼容 DOM 的浏览器中,传入事件处理程序中的 event 对 象有一个 target 属性,值为 document;而 IE8 及之前版本则未提供任何属性。
    * scroll 事件
    1. 虽然 scroll 事件是在 window 对象上发生的,但它实际表示的则是页面中相应元素的变化。
    2. 在混 杂模式下,可以通过元素的 scrollLeft 和 scrollTop 来监控到这一变化;
    3. 而在标准模式下, 除 Safari 之外的所有浏览器都会通过元素来反映这一变化(Safari 仍然基于跟踪滚动位 置)
    EventUtil.addHandler(window, "scroll", function(event){
        if (document.compatMode == "CSS1Compat"){
            alert(document.documentElement.scrollTop);
        } else {
            alert(document.body.scrollTop);
        }
    });
    

    (2) 焦点事件

    焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与 document.hasFocus()方法document.activeElement 属性配合,可以知晓用户在页面上的行踪。

    * 6 个焦点事件:
    1. blur:在元素失去焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
    2. DOMFocusIn:在元素获得焦点时触发。这个事件与 HTML 事件 focus 等价,但它冒泡。只有Opera 支持这个事件。DOM3 级事件废弃了 DOMFocusIn,选择了 focusin。
    3. DOMFocusOut:在元素失去焦点时触发。这个事件是 HTML 事件 blur 的通用版本。只有 Opera支持这个事件。DOM3 级事件废弃了 DOMFocusOut,选择了 focusout。
    4. focus:在元素获得焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
    5. focusin:在元素获得焦点时触发。这个事件与 HTML 事件 focus 等价,但它冒泡。支持这个事件的浏览器有 IE5.5+、Safari 5.1+、Opera 11.5+和 Chrome。
    6. focusout:在元素失去焦点时触发。这个事件是 HTML 事件 blur 的通用版本。支持这个事件的浏览器有 IE5.5+、Safari 5.1+、Opera 11.5+和 Chrome。
    * 当焦点从页面中的一个元素移动到另一个元素,会依次触发下列事件:

    (1) focusout 在失去焦点的元素上触发;
    (2) focusin 在获得焦点的元素上触发;
    (3) blur 在失去焦点的元素上触发;
    (4) DOMFocusOut 在失去焦点的元素上触发;
    (5) focus 在获得焦点的元素上触发;
    (6) DOMFocusIn 在获得焦点的元素上触发。

    *要确定浏览器是否支持这些事件
    var isSupported = document.implementation.hasFeature("FocusEvent", "3.0");
    

    (4) 鼠标与滚轮事件

    DOM3 级事件中定 义了 9 个鼠标事件:

    1. click:在用户单击主鼠标按钮(一般是左边的按钮)或者按下回车键时触发。这一点对确保 易访问性很重要,意味着 onclick 事件处理程序既可以通过键盘也可以通过鼠标执行。
    2. dblclick:在用户双击主鼠标按钮(一般是左边的按钮)时触发。从技术上说,这个事件并不 是 DOM2 级事件规范中规定的,但鉴于它得到了广泛支持,所以 DOM3 级事件将其纳入了标准。
    3. mousedown:在用户按下了任意鼠标按钮时触发。不能通过键盘触发这个事件。
    4. mouseenter:在鼠标光标从元素外部首次移动到元素范围之内时触发。这个事件不冒泡,而且 在光标移动到后代元素上不会触发。DOM2 级事件并没有定义这个事件,但 DOM3 级事件将它纳入了规范。IE、Firefox 9+和 Opera 支持这个事件。
    5. mouseleave:在位于元素上方的鼠标光标移动到元素范围之外时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发。DOM2 级事件并没有定义这个事件,但 DOM3 级事件将它纳入了规范。IE、Firefox 9+和 Opera 支持这个事件。
    6. mousemove:当鼠标指针在元素内部移动时重复地触发。不能通过键盘触发这个事件。
    7. mouseout:在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的另 14 一个元素可能位于前一个元素的外部,也可能是这个元素的子元素。不能通过键盘触发这个事件。
    8. mouseover:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触 发。不能通过键盘触发这个事件。
    9. mouseup:在用户释放鼠标按钮时触发。不能通过键盘触发这个事件。

    mousedown 、mouseup 、click 、dblclick 4 个事件触发的顺序始终如下:

    (1) mousedown
    (2) mouseup
    (3) click
    (4) mousedown
    (5) mouseup
    (6) click
    (7) dblclick

    检测浏览器是否支持以上 DOM2 级事件(除 dbclick、mouseenter 和mouseleave 之外):

    var isSupported = document.implementation.hasFeature("MouseEvents", "2.0");
    

    检测浏览器是否支持上面的所有事件,可以使用以下代码:

    var isSupported = document.implementation.hasFeature("MouseEvent", "3.0")
    
    *客户区坐标位置

    鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象clientXclientY 属性中。所有浏览器都支持这两个属性,它们的值表示事件发生时鼠标指针在视口中的水平 和垂直坐标

    JavaScript 高级程序设计(第13章 事件)_第3张图片

    var div = document.getElementById("myDiv");
    EventUtil.addHandler(div, "click", function(event){
        event = EventUtil.getEvent(event);
        alert("Client coordinates: " + event.clientX + "," + event.clientY);
        });
    
    * 页面坐标位置
    1. 页面坐标通过事件对象的 pageXpageY属性,能告诉你事件是在页面中的什么位置发生的。换句话说,这两个属性表示鼠标光标在页面中的位置,因此坐标是从页面本身而非视口的左边和顶边计算的。
    var div = document.getElementById("myDiv");
        EventUtil.addHandler(div, "click", function(event){
            event = EventUtil.getEvent(event);
            alert("Page coordinates: " + event.pageX + "," + event.pageY);
        });
    

    在页面没有滚动的情况下,pageX 和 pageY 的值与 clientX 和 clientY 的值相等。

    1. IE8 及更早版本不支持事件对象上的页面坐标,不过使用客户区坐标和滚动信息可以计算出来。这 时候需要用到 document.body(混杂模式)或 document.documentElement(标准模式)中的 scrollLeft 和 scrollTop 属性。
    var div = document.getElementById("myDiv");
        EventUtil.addHandler(div, "click", function(event){
            event = EventUtil.getEvent(event);
            var pageX = event.pageX,
                pageY = event.pageY;
            if (pageX === undefined){
                pageX = event.clientX + (document.body.scrollLeft ||
                        document.documentElement.scrollLeft);
            }
            if (pageY === undefined){
                pageY = event.clientY + (document.body.scrollTop ||
                        document.documentElement.scrollTop);
            }
            alert("Page coordinates: " + pageX + "," + pageY);
    });
    
    *屏幕坐标位置

    通 过 screenXscreenY属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。

    JavaScript 高级程序设计(第13章 事件)_第4张图片

    *修改键
    1. 修改键就是Shift、Ctrl、Alt 和 Meta(在 Windows 键盘中是 Windows 键,在苹果机中 是 Cmd 键),它们经常被用来修改鼠标事件的行为。
    2. DOM 为此规定了 4 个属性,表示这些修改键的状 态:shiftKey、ctrlKey、altKey 和 metaKey。这些属性中包含的都是布尔值,如果相应的键被按 下了,则值为 true,否则值为 false。
    var div = document.getElementById("myDiv");
    EventUtil.addHandler(div, "click", function(event){
        event = EventUtil.getEvent(event);
        var keys = new Array();
        if (event.shiftKey){
            keys.push("shift");
    }
        if (event.ctrlKey){
            keys.push("ctrl");
    }
        if (event.altKey){
            keys.push("alt");
    }
        if (event.metaKey){
            keys.push("meta");
    }
        alert("Keys: " + keys.join(","));
    });
    
    *相关元素
    1. 在发生 mouseover 和 mouserout 事件时,还会涉及更多的元素。这两个事件都会涉及把鼠标指 针从一个元素的边界之内移动到另一个元素的边界之内。
      (1) 对mouseover 事件而言,事件的主目标是获 得光标的元素,而相关元素就是那个失去光标的元素。
      (2) 对 mouseout 事件而言,事件的主目标是失去光标的元素,而相关元素则是获得光标的元素。
    2. DOM 通过 event 对象的 relatedTarget 属性提供了相关元素的信息。这个属性只对于 mouseover 和 mouseout 事件才包含值;对于其他事件,这个属性的值是 null。
    3. E8 及之前版本不支持 relatedTarget 属性,但提供了保存着同样信息的不同属性。在 mouseover 事件触发时,IE 的 fromElement 属性中保 存了相关元素;在 mouseout 事件触发时,IE 的 toElement 属性中保存着相关元素。

    跨浏览器取得相关元素的方法添加到 EventUtil 对象中:

    var EventUtil = { 
        //省略了其他代码
        getRelatedTarget: function(event){
            if (event.relatedTarget){
                return event.relatedTarget;
            } else if (event.toElement){
                return event.toElement;
            } else if (event.fromElement){
                return event.fromElement;
            } else {
                return null;
            }
    },
    //省略了其他代码 
    };
    
    *鼠标按钮
    1. 只有在主鼠标按钮被单击(或键盘回车键被按下)时才会触发 click 事件,因此检测按钮的信息 并不是必要的。但对于 mousedown 和 mouseup 事件来说,则在其 event 对象存在一个 button 属性, 表示按下或释放的按钮。
    2. DOM 的 button 属性可能有如下 3 个值:0 表示主鼠标按钮,1 表示中间的鼠 标按钮(鼠标滚轮按钮),2 表示次鼠标按钮。在常规的设置中,主鼠标按钮就是鼠标左键,而次鼠标按钮就是鼠标右键。

    IE8 及之前版本button 属性:

    (1) 0:表示没有按下按钮。
    (2) 1:表示按下了主鼠标按钮。
    (3) 2:表示按下了次鼠标按钮。
    (4) 3:表示同时按下了主、次鼠标按钮。
    (5) 4:表示按下了中间的鼠标按钮。
    (6) 5:表示同时按下了主鼠标按钮和中间的鼠标按钮。
    (7) 6:表示同时按下了次鼠标按钮和中间的鼠标按钮。
    (8) 7:表示同时按下了三个鼠标按钮。

    var EventUtil = { //省略了其他代码
    getButton: function(event){
    if (document.implementation.hasFeature("MouseEvents", "2.0")){
            return event.button;
            } else {
                switch(event.button){
                    case 0:
                    case 1:
                    case 3:
                    case 5:
                    case 7:
                        return 0;
                    case 2:
                    case 6:
                        return 2;
                    case 4:
                        return 1;
    } }
    },
    //省略了其他代码 
    };
    
    var div = document.getElementById("myDiv");
    EventUtil.addHandler(div, "mousedown", function(event){
        event = EventUtil.getEvent(event);
        alert(EventUtil.getButton(event));
    })
    
    *更多的事件信息

    DOM2 级事件”规范在 event 对象中还提供了detail 属性,用于给出有关事件的更多信息。对于鼠标事件来说,detail 中包含了一个数值,表示在给定位置上发生了多少次单击。在同一个元素上 相继地发生一次 mousedown 和一次 mouseup 事件算作一次单击。detail 属性从 1 开始计数,每次单 击发生后都会递增。如果鼠标在 mousedown 和 mouseup 之间移动了位置,则 detail 会被重置为 0。

    *鼠标滚轮事件
    1. 当用 户通过鼠标滚轮与页面交互、在垂直方向上滚动页面时(无论向上还是向下),就会触发mousewheel 事件
    2. 这个事件可以在任何元素上面触发,最终会冒泡到 document(IE8)或 window(IE9、Opera、 Chrome 及 Safari)对象。
    3. 与 mousewheel 事件对应的 event 对象除包含鼠标事件的所有标准信息外, 还包含一个特殊的wheelDelta 属性。当用户向前滚动鼠标滚轮时,wheelDelta 是 120 的倍数;当用 户向后滚动鼠标滚轮时,wheelDelta 是120 的倍数。
    4. 在 Opera 9.5 之前的版本中,wheelDelta 值的正负号是颠倒的。
      Firefox 支持一个名为DOMMouseScroll的类似事件,也是在鼠标滚轮滚动时触发。与 mousewheel 事件一样,DOMMouseScroll 也被视为鼠标事件,因而包含与鼠标事件有关的所有属性。而有关鼠标滚轮的信息则保存在 detail 属性中,当向前滚动鼠标滚轮时,这个属性的值是-3 的倍数,当向后滚动 鼠标滚轮时,这个属性的值是 3 的倍数。

    跨浏览器环境下的解决方案:

    var EventUtil = { 
    //省略了其他代码
    getWheelDelta: function(event){
    if (event.wheelDelta){ 12
        return (client.engine.opera && client.engine.opera < 9.5 ?
                -event.wheelDelta : event.wheelDelta);
    } else {
        return -event.detail * 40;
    }
    },
    //省略了其他代码
     };
    
    (function(){
            function handleMouseWheel(event){
                event = EventUtil.getEvent(event);
                var delta = EventUtil.getWheelDelta(event);
                alert(delta);
    }
    EventUtil.addHandler(document, "mousewheel", handleMouseWheel);
    EventUtil.addHandler(document, "DOMMouseScroll", handleMouseWheel);
    })();
    
    *触摸设备
    1. 不支持 dblclick 事件。双击浏览器窗口会放大画面,而且没有办法改变该行为。
    2. 轻击可单击元素会触发 mousemove 事件。如果此操作会导致内容变化,将不再有其他事件发生;如果屏幕没有因此变化,那么会依次发生 mousedown、mouseup 和 click 事件。轻击不可单 击的元素不会触发任何事件。可单击的元素是指那些单击可产生默认操作的元素(如链接),或 者那些已经被指定了 onclick 事件处理程序的元素。
    3. mousemove 事件也会触发 mouseover 和 mouseout 事件。
    4. 两个手指放在屏幕上且页面随手指移动而滚动时会触发 mousewheel 和 scroll 事件。
    *无障碍性问题
    1. 使用 click 事件执行代码。有人指出通过 onmousedown 执行代码会让人觉得速度更快,对视 力正常的人来说这是没错的。但是,在屏幕阅读器中,由于无法触发 mousedown 事件,结果就 会造成代码无法执行。
    2. 不要使用onmouseover向用户显示新的选项。原因同上,屏幕阅读器无法触发这个事件。如果 确实非要通过这种方式来显示新选项,可以考虑添加显示相同信息的键盘快捷方式。
    3. 不要使用 dblclick 执行重要的操作。键盘无法触发这个事件。

    (4) 键盘与文本事件

    3 个键盘事件:

    1. keydown:当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件。
    2. keypress:当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件。按下 Esc 键也会触发这个事件。Safari 3.1 之前的版本也会在用户按下非字符键时触发 keypress事件。
    3. keyup:当用户释放键盘上的键时触发。

    只有一个文本事件:textInput:

    这个事件是对 keypress 的补充,用意是在将文本显示给用户之 前更容易拦截文本。在文本插入文本框之前会触发 textInput 事件。

    *键码

    在发生 keydown 和 keyup 事件时,event 对象keyCode 属性中会包含一个代码,与键盘上一 个特定的键对应。对数字字母字符键,keyCode 属性的值与ASCII 码中对应小写字母或数字的编码相同

    var textbox = document.getElementById("myText");
    EventUtil.addHandler(textbox, "keyup", function(event){
        event = EventUtil.getEvent(event);
        alert(event.keyCode);
    });
    

    非字符键的键码:

    JavaScript 高级程序设计(第13章 事件)_第5张图片

    JavaScript 高级程序设计(第13章 事件)_第6张图片
    非字符键的键码
    *字符编码

    IE9、Firefox、Chrome 和 Safari 的 event 对象都支持一个 charCode 属性,这个属性只有在发生 keypress 事件时才包含值,而且这个值是按下的那个键所代表字符的 ASCII 编码。此时的 keyCode 通常等于 0 或者也可能等于所按键的键码。IE8 及之前版本和 Opera 则是在 keyCode 中保存字符的 ASCII 编码。
    跨浏览器的方式取得字符编码:

    var EventUtil = { 
            //省略的代码
            getCharCode: function(event){
                if (typeof event.charCode == "number"){
                    return event.charCode;
                } else {
                    return event.keyCode;
                }
            },
            //省略的代码
    };
    var textbox = document.getElementById("myText");
        EventUtil.addHandler(textbox, "keypress", function(event){
            event = EventUtil.getEvent(event);
            alert(EventUtil.getCharCode(event));
    });
    
    * DOM3 级变化

    1.DOM3级事件中的键盘事件,不再包含 charCode 属性,而是包含两个新属性:keychar
    (1) key 属性是为了取代 keyCode 而新增的,它的值是一个字符串。在按下某个字符键时,key的值就是相应的文本字符(如“k”或“M”);在按下非字符键时, key 的值是相应键的名(如“Shift” 或“Down”)。
    (2) char 属性在按下字符键时的行为与 key 相同,但在按下非字符键时值为 null。

    1. IE9 支持 key 属性,但不支持 char 属性。Safari 5 和 Chrome 支持名为 keyIdentifier 的属性, 在按下非字符键(例如 Shift)的情况下与 key 的值相同。对于字符键,keyIdentifier 返回一个格式 类似“U+0000”的字符串,表示 Unicode 值。
    var textbox = document.getElementById("myText");
        EventUtil.addHandler(textbox, "keypress", function(event){
            event = EventUtil.getEvent(event);
            var identifier = event.key || event.keyIdentifier;
            if (identifier){
            alert(identifi er);
        }
    });
    
    1. DOM3 级事件还添加了一个名为location 的属性,这是一个数值,表示按下了什么位置上的键: 0 表示默认键盘,1 表示左侧位置(例如左位的 Alt 键),2 表示右侧位置(例如右侧的 Shift 键),3 表示 数字小键盘,4 表示移动设备键盘(也就是虚拟键盘),5 表示手柄(如任天堂 Wii 控制器)。IE9 支持这 个属性。Safari 和 Chrome 支持名为 keyLocation 的等价属性,但即有 bug——值始终是 0,除非按下 了数字键盘(此时,值 为 3);否则,不会是 1、2、4、5。
    var textbox = document.getElementById("myText");
        EventUtil.addHandler(textbox, "keypress", function(event){
            event = EventUtil.getEvent(event);
            var loc = event.location || event.keyLocation;
            if (loc){
            alert(loc);
        }
    });
    

    4.event 对象添加了 getModifierState()方法。这个方法接收一个参数,即等于 Shift、 Control、AltGraph 或 Meta 的字符串,表示要检测的修改键。如果指定的修改键是活动的(也就是 处于被按下的状态),这个方法返回 true,否则返回 false。

    var textbox = document.getElementById("myText");
    EventUtil.addHandler(textbox, "keypress", function(event){
        event = EventUtil.getEvent(event);
        if (event.getModifierState){
            alert(event.getModifierState("Shift"));
    }
    });
    
    *textInput 事件
    1. 当用户在可编辑区域中输入字符时,就会触发这个事件。
    1. 这个用于替代 keypress 的 textInput 事件的行为稍有不同。
      (1)任何可以获得焦点的元素都可以触发 keypress 事件,但只有可编辑区域才能触发 textInput 事件。
      (2) textInput 事件只会在用户按下能够输入实际字符的键时才会被触发,而 keypress 事件则在按下那些能够影响文本显示的键时也会触发(例如退格键)。
    1. event 对象中还包含一个 data 属性,这个属 性的值就是用户输入的字符(而非字符编码)。换句话说,用户在没有按上档键的情况下按下了 S 键, 19 data 的值就是"s",而如果在按住上档键时按下该键,data 的值就是"S"。
    var textbox = document.getElementById("myText");
    EventUtil.addHandler(textbox, "textInput", function(event){ event = EventUtil.getEvent(event);
    alert(event.data);
    });
    
    1. event 对象上还有一个属性,叫 inputMethod,表示把文本输入到文本框中的方式。
      (1) 0,表示浏览器不确定是怎么输入的。
      (2) 1,表示是使用键盘输入的。
      (3) 2,表示文本是粘贴进来的。
      (4) 3,表示文本是拖放进来的。
      (5) 4,表示文本是使用 IME 输入的。
      (6) 5,表示文本是通过在表单中选择某一项输入的。
      (7) 6,表示文本是通过手写输入的(比如使用手写笔)。
      (8) 7,表示文本是通过语音输入的。
      (9) 8,表示文本是通过几种方法组合输入的。
      (10) 9,表示文本是通过脚本输入的。

    (5) 复合事件

    复合事件(composition event)是 DOM3 级事件中新添加的一类事件,用于处理 IME 的输入序列IME(Input Method Editor,输入法编辑器)可以让用户输入在物理键盘上找不到的字符。例如,使用拉 丁文键盘的用户通过 IME 照样能输入日文字符。IME 通常需要同时按住多个键,但最终只输入一个字 符。

    三种复合事件:

    1. compositionstart:在 IME 的文本复合系统打开时触发,表示要开始输入了。
    2. compositionupdate:在向输入字段中插入新字符时触发。
    3. compositionend:在 IME 的文本复合系统关闭时触发,表示返回正常键盘输入状态。

    在触发复合事件时,目标是接收文本的输入字段,data属性

    1. 如果在 compositionstart 事件发生时访问,包含正在编辑的文本(例如,已经选中的需要马上替换的文本);
    2. 如果在 compositionupdate 事件发生时访问,包含正插入的新字符;
    3. 如果在 compositionend 事件发生时访问,包含此次输入会话中插入的所有字符。
    var textbox = document.getElementById("myText");
    EventUtil.addHandler(textbox, "compositionstart", function(event){ 
        event = EventUtil.getEvent(event);
        alert(event.data);
    });
    EventUtil.addHandler(textbox, "compositionupdate", function(event){
        event = EventUtil.getEvent(event);
        alert(event.data);
    });
    EventUtil.addHandler(textbox, "compositionend", function(event){ 
        event = EventUtil.getEvent(event);
        alert(event.data);
    });
    

    (6) 变动事件

    DOM2 级的变动(mutation)事件能在 DOM 中的某一部分发生变化时给出提示。变动事件是为 XML 或 HTML DOM 设计的,并不特定于某种语言。

    DOM2 级定义了如下变动事件:

    1. DOMSubtreeModified:在 DOM 结构中发生任何变化时触发。这个事件在其他任何事件触发 10 后都会触发。
    2. DOMNodeInserted:在一个节点作为子节点被插入到另一个节点中时触发。
    3. DOMNodeRemoved:在节点从其父节点中被移除时触发。
    4. DOMNodeInsertedIntoDocument:在一个节点被直接插入文档或通过子树间接插入文档之后触发。这个事件在 DOMNodeInserted 之后触发。
    5. DOMNodeRemovedFromDocument:在一个节点被直接从文档中移除或通过子树间接从文档中移
      除之前触发。这个事件在 DOMNodeRemoved 之后触发。
    6. DOMAttrModified:在特性被修改之后触发。
    7. DOMCharacterDataModified:在文本节点的值发生变化时触发。
    * 删除节点
    1. 在使用 removeChild()或 replaceChild()从 DOM 中删除节点时,首先会触发 DOMNodeRemoved事件。这个事件的目标(event.target)是被删除的节点,而 event.relatedNode 属性中包含着对 目标节点父节点的引用。在这个事件触发时,节点尚未从其父节点删除,因此其 parentNode 属性仍然 指向父节点(与 event.relatedNode 相同)。这个事件会冒泡,因而可以在 DOM 的任何层次上面处 理它。
    2. 如果被移除的节点包含子节点,那么在其所有子节点以及这个被移除的节点上会相继触发DOMNodeRemovedFromDocument 事件。但这个事件不会冒泡,所以只有直接指定给其中一个子节点的 事件处理程序才会被调用。这个事件的目标是相应的子节点或者那个被移除的节点,除此之外 event 对象中不包含其他信息。
    3. 紧随其后触发的是DOMSubtreeModified 事件。这个事件的目标是被移除节点的父节点;此时的 event 对象也不会提供与事件相关的其他信息。
    
        
        
            Node Removal Events Example
        
        
            
    • Item 1
    • Item 2
    • Item 3

    在这个例子中,我们假设要移除

      元素。此时,就会依次触发以下事件:

      (1) 在

        元素上触发 DOMNodeRemoved 事件。relatedNode 属性等于 document.body。
        (2) 在
          元素上触发 DOMNodeRemovedFromDocument 事件。
          (3) 在身为
            元素子节点的每个
          • 元素及文本节点上触发 DOMNodeRemovedFromDocument
            事件。
            (4) 在 document.body 上触发 DOMSubtreeModified 事件,因为
              元素是 document.body
              的直接子元素。

      *插入节点
      1. 在使用 appendChild()、replaceChild()或 insertBefore()向 DOM 中插入节点时,首先会 触发 DOMNodeInserted 事件。这个事件的目标是被插入的节点,而 event.relatedNode 属性中包含 一个对父节点的引用。在这个事件触发时,节点已经被插入到了新的父节点中。这个事件是冒泡的,因 此可以在 DOM 的各个层次上处理它。
      2. 紧接着,会在新插入的节点上面触发DOMNodeInsertedIntoDocument 事件。这个事件不冒泡, 因此必须在插入节点之前为它添加这个事件处理程序。这个事件的目标是被插入的节点,除此之外 event 对象中不包含其他信息。
      3. 最后一个触发的事件是 DOMSubtreeModified,触发于新插入节点的父节点。

      (7) HTML5 事件

      * contextmenu 事件

      上下文菜单的概念:即通过单击鼠标右键可以调出上下文菜单。

      1. contextmenu 事件:用以表示何时应该显示上下文菜单,以便开发人员取消默认的上下文菜单而提供自定义的菜单。
      2. contextmenu 事件是冒泡的,因此可以为 document 指定一个事件处理程序,用以处理页面中发生的所有此类事件。
      3. 这个事件的目标是发生用户操作的元素。在所有浏览器中都可以取消这个事件: 在兼容 DOM 的浏览器中,使用 event.preventDefalut();在 IE 中,将 event.returnValue 的值 设置为 false。
      4. 通常使用 contextmenu 事件来显示自定义的上下文菜单,而使用onclick 事件处理程序来隐藏该菜单
      
          
          
              ContextMenu Event Example
          
          
              
      Right click or Ctrl+click me to get a custom context menu. Click anywhere else to get the default context menu.
      EventUtil.addHandler(window, "load", function(event){ var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "contextmenu", function(event){ event = EventUtil.getEvent(event); EventUtil.preventDefault(event); var menu = document.getElementById("myMenu"); menu.style.left = event.clientX + "px"; menu.style.top = event.clientY + "px"; menu.style.visibility = "visible"; }); EventUtil.addHandler(document, "click", function(event){ document.getElementById("myMenu").style.visibility = "hidden"; }); });
      *beforeunload 事件
      1. 发生在 window 对象上的 beforeunload 事件,是为了让开发人员有可能在页面卸载前阻止这一操作。这个事件会在浏览器卸载页面之前触发,可以通过它来取消卸载并继续使用原有页面。 但是,不能彻底取消这个事件,因为那就相当于让用户无法离开当前页面了。为此,这个事件的意图是 将控制权交给用户。显示的消息会告知用户页面行将被卸载(正因为如此才会显示这个消息),询问用 户是否真的要关闭页面,还是希望继续留下来。
      2. event.returnValue的值设置为要显示给用户的字符串(对IE 及 Fiefox 而言),同时作为函数的值返回(对 Safari 和 Chrome 而言)。
      *DOMContentLoaded 事件

      1.DOMContentLoaded 事件在形成完整的 DOM 树之后就会触发, 不理会图像、JavaScript 文件、CSS 文件或其他资源是否已经下载完毕。

      1. 要处理 DOMContentLoaded 事件,可以为document 或 window添加相应的事件处理程序(尽管 这个事件会冒泡到 window,但它的目标实际上是 document)。
      2. DOMContentLoaded 事件对象不会提供任何额外的信息(其 target 属性是 document)。
      *readystatechange 事件
      1. readystatechange 事件的目的是提供与文档或元素的加载状态有关的信息。
      2. 支持 readystatechange 事件的每个对象都有一个 readyState 属性,可能包含下列 5 个值中的一个:
        (1)uninitialized(未初始化):对象存在但尚未初始化。
        (2) loading(正在加载):对象正在加载数据。
        (3) loaded(加载完毕):对象加载数据完成。
        (4) interactive(交互):可以操作对象了,但还没有完全加载。
        (5) complete(完成):对象已经加载完毕。
      EventUtil.addHandler(window, "load", function(){
              var script = document.createElement("script");
              EventUtil.addHandler(script, "readystatechange", function(event){
                   event = EventUtil.getEvent(event);
                  var target = EventUtil.getTarget(event);
                  if (target.readyState == "loaded" || target.readyState == "complete"){
                     EventUtil.removeHandler(target, "readystatechange", arguments. callee); 
                     alert("Script Loaded");
                  }
               });
              script.src = "example.js";
              document.body.appendChild(script);
      });
      
      *pageshow 和 pagehide 事件

      Firefox 和 Opera 有一个特性,名叫“往返缓存”(back-forward cache,或 bfcache),可以在用户使用浏览器的“后退”和“前进”按钮时加快页面的转换速度。这个缓存中不仅保存着页面数据,还保存 了 DOM 和 JavaScript 的状态;实际上是将整个页面都保存在了内存里。如果页面位于 bfcache 中,那么 再次打开该页面时就不会触发 load 事件。

      1. 第一个事件就是 pageshow,这个事件在页面显示时触发,无论该页面是否来自 bfcache。在重新加载的页面中,pageshow 会在 load 事件触发后触发;而对于 bfcache 中的页面,pageshow 会在页面状态完全恢复的那一刻触发。
        (1) 这个事件的目标是 document,但必须将其事件处理 程序添加到 window。
        (2) pageshow 事件的 event 对象还包含一个名为 persisted 的布尔值属性。 如果页面被保存在了 bfcache 中,则这个属性的值为 true;否则,这个属性的值为 false。
      2. pagehide 事件,该事件会在浏览器卸载页面的时候触发,而且是在 unload 事件之前触发。
        (1) 与 pageshow 事件一样,pagehide 在 document 上面触发,但其事件处理程 序必须要添加到 window 对象。
        (2) 这个事件的 event 对象也包含persisted 属性,对于 pagehide 事件,如果 页面在卸载之后会被保存在 bfcache 中,那么 persisted 的值也会被设置为 true。因此,当第一次触 发 pageshow 时,persisted 的值一定是 false,而在第一次触发 pagehide 时,persisted 就会变 成 true(除非页面不会被保存在 bfcache 中)。
      * hashchange 事件
      1. hashchange 事件:以便在 URL 的参数列表(及 URL 中“#”号后面的所有字符串) 发生变化时通知开发人员。
      2. 必须要把 hashchange 事件处理程序添加给 window 对象,然后 URL 参数列表只要变化就会调用它。
      3. event 对象应该额外包含两个属性:oldURLnewURL。这两个属性分别保存着参数列表 变化前后的完整 URL。

      (8) 设备事件

      *orientationchange 事件

      苹果公司为移动 Safari 中添加了 orientationchange 事件,以便开发人员能够确定用户何时将设 备由横向查看模式切换为纵向查看模式。移动 Safari 的 window.orientation 属性中可能包含 3 个值: 0 表示肖像模式,90 表示向左旋转的横向模式(“主屏幕”按钮在右侧),-90 表示向右旋转的横向模 式(“主屏幕”按钮在左侧)。

      5.内存和性能

      (1) 事件委托

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

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

      (2) 移除事件处理程序

      “空事件处理程序”两种情况:

      1. 从文档中移除带有事件处理程序的元素时,带有事件处理程序的元素被 innerHTML 删除 了,那么原来添加到元素中的事件处理程序极有可能无法被当作垃圾回收。如果你知道某个元素即将被移除,那么最好手工移除事件处理 程序element.onclick = null
      2. 如果在页面被卸载之前没 有清理干净事件处理程序,那它们就会滞留在内存中。最好的做法是在页面卸载之前,先通过 onunload 事件处理程序移除所有事件处理程序。

      6. 模拟事件

      (1) DOM中的事件模拟

      创建模拟事件的步骤:

      1. document 对象上的 createEvent()方法创建 event 对象。这个方法接收一个参数,即表示要创建的事件类型的字符串。

      事件类型的字符串:

      (1) UIEvents:一般化的 UI 事件。鼠标事件和键盘事件都继承自 UI 事件。DOM3 级中是 UIEvent。
      (2) MouseEvents:一般化的鼠标事件。DOM3 级中是 MouseEvent。
      (3) MutationEvents:一般化的 DOM 变动事件。DOM3 级中是 MutationEvent。
      (4) HTMLEvents:一般化的 HTML 事件。没有对应的 DOM3 级事件(HTML 事件被分散到其他类
      别中)。

      1. 在创建了 event 对象之后,还需要使用与事件有关的信息对其进行初始化。
      2. 使用 dispatchEvent()方法触发事件,传入一个参数,即表示要触发事件 的 event 对象。
      *模拟鼠标事件

      创建鼠标事件对象的方法是 为 createEvent()传入字符串"MouseEvents"。返回的对象有一个名为 initMouseEvent()方法, 用于指定与该鼠标事件有关的信息。这个方法接收15 个参数,分别与鼠标事件中每个典型的属性一一 对应:

      (1) type(字符串):表示要触发的事件类型,例如"click"。
      (2) bubbles(布尔值):表示事件是否应该冒泡。为精确地模拟鼠标事件,应该把这个参数设置为
      true。
      (3) cancelable(布尔值):表示事件是否可以取消。为精确地模拟鼠标事件,应该把这个参数设置为 true。
      (4) view(AbstractView):与事件关联的视图。这个参数几乎总是要设置为 document.defaultView。
      (5) detail(整数):与事件有关的详细信息。这个值一般只有事件处理程序使用,但通常都设置为 0。
      (6) screenX(整数):事件相对于屏幕的 X 坐标。
      (7) screenY(整数):事件相对于屏幕的 Y 坐标。
      (8) clientX(整数):事件相对于视口的 X 坐标。
      (9) clientY(整数):事件想对于视口的 Y 坐标。
      (10) ctrlKey(布尔值):表示是否按下了 Ctrl 键。默认值为 false。
      (11) altKey(布尔值):表示是否按下了 Alt 键。默认值为 false。
      (12) shiftKey(布尔值):表示是否按下了 Shift 键。默认值为 false。
      (13) metaKey(布尔值):表示是否按下了 Meta 键。默认值为 false。
      (14) button(整数):表示按下了哪一个鼠标键。默认值为 0。
      (15) relatedTarget(对象):表示与事件相关的对象。这个参数只在模拟 mouseover 或 mouseout时使用。

      var btn = document.getElementById("myBtn");
      //创建事件对象
      var event = document.createEvent("MouseEvents");
      //初始化事件对象
      event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0,false, false, false, false, 0, null);
      //触发事件
      btn.dispatchEvent(event);
      
      *模拟键盘事件

      DOM3 级规定,调用 createEvent()并传入"KeyboardEvent"就可以创建一个键盘事件。返回的 7 事件对象会包含一个 initKeyEvent()方法,这个方法接收下列参数。

      (1) type(字符串):表示要触发的事件类型,如"keydown"。
      (2) bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为 true。
      (3) cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为 true。 view(AbstractView):与事件关联的视图。这个参数几乎总是要设置为 document.defaultView。
      (4) key(布尔值):表示按下的键的键码。
      (5) location(整数):表示按下了哪里的键。0 表示默认的主键盘,1 表示左,2 表示右,3 表示
      数字键盘,4 表示移动设备(即虚拟键盘),5 表示手柄。
      (6) modifiers(字符串):空格分隔的修改键列表,如"Shift"。
      (7) repeat(整数):在一行中按了这个键多少次

      *模拟其他事件
      1. 模拟变动事件,可以使用 createEvent("MutationEvents")创建一个包含 initMutationEvent()方法的变动事件对象。这个方法接受的参数包括:type、bubbles、 cancelable、relatedNode、preValue、newValue、attrName 和 attrChange
      1. 模拟 HTML 事件,同样需要先创建一个 event 对象——通过 createEvent("HTMLEvents"), 然后再使用这个对象的 initEvent()方法来初始化它。
      var event = document.createEvent("HTMLEvents");
      event.initEvent("focus", true, false);
      target.dispatchEvent(event);
      
      *自定义 DOM 事件

      DOM3 级还定义了“自定义事件”。自定义事件不是由 DOM 原生触发的,它的目的是让开发人员创建自己的事件。要创建新的自定义事件,可以调用 createEvent("CustomEvent")。返回的对象有 一个名为initCustomEvent()的方法,接收如下 4 个参数。

      (1) type(字符串):触发的事件类型,例如"keydown"。
      (2) bubbles(布尔值):表示事件是否应该冒泡。
      (3) cancelable(布尔值):表示事件是否可以取消。
      (4) detail(对象):任意值,保存在 event 对象的 detail 属性中。

      (2) IE中的事件模拟

      1. 调用 document.createEventObject()方法可以在 IE 中创建 event 对象。但与 DOM 方式不同 的是,这个方法不接受参数,结果会返回一个通用的 event 对象。
      2. 然后,你必须手工为这个对象添加 所有必要的信息(没有方法来辅助完成这一步骤)。
      3. 最后一步就是在目标上调用 fireEvent()方法,这 个方法接受两个参数:事件处理程序的名称和 event 对象。在调用 fireEvent()方法时,会自动为 event 对象添加 srcElement 和 type 属性;其他属性则都是必须通过手工添加的。
      var btn = document.getElementById("myBtn");
      //创建事件对象
      var event = document.createEventObject();
      //初始化事件对象
      event.screenX = 100;
      event.screenY = 0;
      event.clientX = 0;
      event.clientY = 0; 
      event.ctrlKey = false; 
      event.altKey = false;
      event.shiftKey = false;
      event.button = 0;
      //触发事件
       btn.fireEvent("onclick", event);
      

      你可能感兴趣的:(JavaScript 高级程序设计(第13章 事件))