JavaScript高级程序设计-事件之事件类型/内存与性能/模拟事件

13.4 事件类型

Web 浏览器中可能发生的事件有很多类型。

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

UI 事件指的是那些不一定与用户操作有关的事件。这些事件在 DOM 规范出现之前,都是以这种或那种形式存在的,而在 DOM 规范中保留是为了向后兼容。

  • DOMActivate:表示元素已经被用户操作(通过鼠标或键盘)激活。这个事件在 DOM3 级事件中被废弃,但 Firefox 2+和 Chrome 支持它。考虑到不同浏览器实现的差异,不建议使用这个事件。
  • load:当页面完全加载后在 window 上面触发,当所有框架都加载完毕时在框架集上面触发,当图像加载完毕时在<img>元素上面触发,或者当嵌入的内容加载完毕时在<object>元素上面触发。
  • unload:当页面完全卸载后在 window 上面触发,当所有框架都卸载后在框架集上面触发,或者当嵌入的内容卸载完毕后在<object>元素上面触发。
  • abort:在用户停止下载过程时,如果嵌入的内容没有加载完,则在<object>元素上面触发。
  • error:当发生 JavaScript 错误时在 window 上面触发,当无法加载图像时在<img>元素上面触发,当无法加载嵌入内容时在<object>元素上面触发,或者当有一或多个框架无法加载时在框架集上面触发。
  • select:当用户选择文本框(<input>或<texterea>)中的一或多个字符时触发。
  • resize:当窗口或框架的大小变化时在 window 或框架上面触发。
  • scroll:当用户滚动带滚动条的元素中的内容时,在该元素上面触发。 <body>元素中包含所加载页面的滚动条。
  1. load 事件
    JavaScript 中最常用的一个事件就是 load。当页面完全加载后(包括所有图像、 JavaScript 文件、CSS 文件等外部资源),就会触发 window 上面的 load 事件。
EventUtil.addHandler(window, "load", function(event){
    alert("Loaded!");
});

与添加其他事件一样,这里也给事件处理程序传入了一个 event 对象。这个 event 对象中不包含有关这个事件的任何附加信息,但在兼容 DOM 的浏览器中, event.target 属性的值会被设置为document,而 IE 并不会为这个事件设置 srcElement 属性。
第二种指定 onload 事件处理程序的方式是为<body>元素添加一个 onload 特性

<!DOCTYPE html>
<html>
<head>
<title>Load Event Example</title>
</head>
    <body onload="alert('Loaded!')">
</body>
</html>

::: tip
根据“DOM2 级事件”规范,应该在 document 而非 window 上面触发 load 事件。但是,所有浏览器都在 window 上面实现了该事件,以确保向后兼容。
:::
在创建新的<img>元素时,可以为其指定一个事件处理程序,以便图像加载完毕后给出提示。此时,最重要的是要在指定 src 属性之前先指定事件

EventUtil.addHandler(window, "load", function(){
    var image = document.createElement("img");
    EventUtil.addHandler(image, "load", function(event){
        event = EventUtil.getEvent(event);
        alert(EventUtil.getTarget(event).src);
    });
    document.body.appendChild(image);
    image.src = "smile.gif";
});

同样的功能也可以通过使用 DOM0 级的 Image 对象实现。在 DOM 出现之前,开发人员经常使用Image 对象在客户端预先加载图像。

EventUtil.addHandler(window, "load", function(){
    var image = new Image();
    EventUtil.addHandler(image, "load", function(event){
        alert("Image loaded!");
    });
    image.src = "smile.gif";
});

<script>元素也会触发 load 事件,以便开发人员确定动态加载的 JavaScript 文件是否加载完毕

EventUtil.addHandler(window, "load", function(){
    var script = document.createElement("script");
    EventUtil.addHandler(script, "load", function(event){
        alert("Loaded");
    });
    script.src = "example.js";
    document.body.appendChild(script);
});

<link>元素上的 load 事件

EventUtil.addHandler(window, "load", function(){
    var link = document.createElement("link");
    link.type = "text/css";
    link.rel= "stylesheet";
    EventUtil.addHandler(link, "load", function(event){
        alert("css loaded");
    });
    link.href = "example.css";
    document.getElementsByTagName("head")[0].appendChild(link);
});
  1. unload 事件
    与 load 事件对应的是 unload 事件,这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生 unload 事件。而利用这个事件最多的情况是清除引用,以避免内存泄漏。与 load 事件类似,也有两种指定 onunload 事件处理程序的方式。
EventUtil.addHandler(window, "unload", function(event){
    alert("Unloaded");
});

指定事件处理程序的第二种方式,也是为<body>元素添加一个特性(与 load 事件相似),

<!DOCTYPE html>
<html>
<head>
    <title>Unload Event Example</title>
</head>
<body onunload="alert('Unloaded!')">
</body>
</html>
  1. resize 事件
    当浏览器窗口被调整到一个新的高度或宽度时,就会触发 resize 事件。这个事件在 window(窗口)上面触发,因此可以通过 JavaScript 或者<body>元素中的 onresize 特性来指定事件处理程序。
EventUtil.addHandler(window, "resize", function(event){
    alert("Resized");
});
  1. scroll 事件
    虽然 scroll 事件是在 window 对象上发生的,但它实际表示的则是页面中相应元素的变化。在混杂模式下,可以通过<body>元素的 scrollLeft 和 scrollTop 来监控到这一变化;
EventUtil.addHandler(window, "scroll", function(event){
    if (document.compatMode == "CSS1Compat"){
        alert(document.documentElement.scrollTop);
    } else {
        alert(document.body.scrollTop);
    }
});
13.4.2 焦点事件

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

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

鼠标事件是 Web 开发中最常用的一类事件,毕竟鼠标还是最主要的定位设备。 DOM3 级事件中定义了 9 个鼠标事件,

  • click:在用户单击主鼠标按钮(一般是左边的按钮)或者按下回车键时触发。这一点对确保易访问性很重要,意味着 onclick 事件处理程序既可以通过键盘也可以通过鼠标执行。
  • dblclick:在用户双击主鼠标按钮(一般是左边的按钮)时触发。从技术上说,这个事件并不是 DOM2 级事件规范中规定的,但鉴于它得到了广泛支持,所以 DOM3 级事件将其纳入了标准。
  • mousedown:在用户按下了任意鼠标按钮时触发。不能通过键盘触发这个事件。
  • mouseenter:在鼠标光标从元素外部首次移动到元素范围之内时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发。 DOM2 级事件并没有定义这个事件,但 DOM3 级事件将它纳入了规范。 IE、 Firefox 9+和 Opera 支持这个事件。
  • mouseleave:在位于元素上方的鼠标光标移动到元素范围之外时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发。 DOM2 级事件并没有定义这个事件,但 DOM3 级事件将它纳入了规范。 IE、 Firefox 9+和 Opera 支持这个事件。
  • mousemove:当鼠标指针在元素内部移动时重复地触发。不能通过键盘触发这个事件。
  • mouseout:在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的另一个元素可能位于前一个元素的外部,也可能是这个元素的子元素。不能通过键盘触发这个事件。
  • mouseover:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。不能通过键盘触发这个事件。
  • mouseup:在用户释放鼠标按钮时触发。不能通过键盘触发这个事件。
    除了 mouseenter 和 mouseleave,所有鼠标事件都会冒泡,也可以被取消,而取消鼠标事件将会影响浏览器的默认行为。
    只有在同一个元素上相继触发 mousedown 和 mouseup 事件,才会触发 click 事件;如果mousedown 或 mouseup 中的一个被取消,就不会触发 click 事件。
  1. 客户区坐标位置
    鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象的 clientX 和clientY 属性中。
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
    event = EventUtil.getEvent(event);
    alert("Client coordinates: " + event.clientX + "," + event.clientY);
});
  1. 页面坐标位置
    通过客户区坐标能够知道鼠标是在视口中什么位置发生的,而页面坐标通过事件对象的 pageX 和pageY 属性
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
    event = EventUtil.getEvent(event);
    alert("Page coordinates: " + event.pageX + "," + event.pageY);
});

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||documentElement.scrollLeft);
    }
    if(pageY === undefined){
        pageY = event.clientY + (document.body.scrollTop||document.documentElement.scrollTop);
    }

    alert("Page coordinates: " + pageX + "," + pageY);
});
  1. 屏幕坐标位置
    鼠标事件发生时,不仅会有相对于浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置。而通过 screenX 和 screenY 属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。
var div = document.getElementById("myDiv");
EventUtil.addHandler(div,"click",function(event){
    event = EventUtil(event);
    alert("screen coordinates:"+event.screenX+","+event.screenY);
})
  1. 修改键
    虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也可以影响到所要采取的操作。
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 和 mouseout 事件时,还会涉及更多的元素。
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 属性,表示按下或释放的按钮。 DOM 的 button 属性可能有如下 3 个值: 0 表示主鼠标按钮, 1 表示中间的鼠标按钮(鼠标滚轮按钮), 2 表示次鼠标按钮。
  • 0:表示没有按下按钮。
  • 1:表示按下了主鼠标按钮。
  • 2:表示按下了次鼠标按钮。
  • 3:表示同时按下了主、次鼠标按钮。
  • 4:表示按下了中间的鼠标按钮。
  • 5:表示同时按下了主鼠标按钮和中间的鼠标按钮。
  • 6:表示同时按下了次鼠标按钮和中间的鼠标按钮。
  • 7:表示同时按下了三个鼠标按钮。
var EventUtil = {
    getButton:function(event){
        if(document.inplementation.hasFeature("MouseEvents","2.0")){
            return event.button;
        }else{
            switch(evemt.button){
                case 0case 1case 3:
                case 5:
                case 7:
                    return 0;
                case 2:
                case 6:
                    return 2;
                case 4:
                    return 1;
            }
        }
    },
};
  1. 更多的事件信息
    “DOM2 级事件”规范在 event 对象中还提供了 detail 属性,用于给出有关事件的更多信息。对于鼠标事件来说, detail 中包含了一个数值,表示在给定位置上发生了多少次单击。在同一个元素上相继地发生一次 mousedown 和一次 mouseup 事件算作一次单击。
  • altLeft: 布尔值,表示是否按下了 Alt 键。 如果 altLeft 的值为 true,则 altKey 的值也为 true。
  • ctrlLeft:布尔值,表示是否按下了 Ctrl 键。如果 ctrlLeft 的值为 true,则 ctrlKey 的值也为 true。
  • offsetX:光标相对于目标元素边界的 x 坐标。
  • offsetY:光标相对于目标元素边界的 y 坐标。
  • shiftLeft:布尔值,表示是否按下了 Shift 键。如果 shiftLeft 的值为 true,则 shiftKey的值也为 true。
  1. 鼠标滚轮事件
    IE 6.0 首先实现了mousewheel事件。此后,Opera、Chrome 和 Safari 也都实现了这个事件。当用户通过鼠标滚轮与页面交互、在垂直方向上滚动页面时(无论向上还是向下),就会触发 mousewheel事件。
    在 Opera 9.5 之前的版本中, wheelDelta 值的正负号是颠倒的。如果你打算支持早期的 Opera 版本,就需要使用浏览器检测技术来确定实际的值,
EventUtil.addHandler(document, "mousewheel", function(event){
    event = EventUtil.getEvent(event);
    var delta = (client.engine.opera && client.engine.opera < 9.5 ?-event.wheelDelta : event.wheelDelta);
    alert(delta);
});

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eX3QHpNS-1579591369555)(/images/frontend-javascript-event-mousescroll.jpg)]
添加事件处理程序

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

用户在使用键盘时会触发键盘事件。“DOM2 级事件”最初规定了键盘事件,但在最终定稿之前又删除了相应的内容。结果,对键盘事件的支持主要遵循的是 DOM0 级。
有 3 个键盘事件,简述如下。

  • keydown:当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件。
  • keypress:当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件。按下 Esc 键也会触发这个事件。 Safari 3.1 之前的版本也会在用户按下非字符键时触发keypress事件。
  • keyup:当用户释放键盘上的键时触发。
    只有一个文本事件: textInput。这个事件是对 keypress 的补充,用意是在将文本显示给用户之前更容易拦截文本。在文本插入文本框之前会触发 textInput 事件
  1. 键码
    在发生 keydown 和 keyup 事件时, event 对象的 keyCode 属性中会包含一个代码,与键盘上一个特定的键对应。
var textbox = document.getElementById("myText");
    EventUtil.addHandler(textbox, "keyup", function(event){
        event = EventUtil.getEvent(event);
        alert(event.keyCode);
});
键 码键 码
退格( Backspace)8数字小键盘197
制表( Tab)9数字小键盘298
回车( Enter)13 数字小键盘399
上档( Shift)16 数字小键盘4100
控制( Ctrl)17 数字小键盘5101
Alt18数字小键盘6102
暂停/中断( Pause/Break)19数字小键盘7103
大写锁定( Caps Lock)20数字小键盘8104
退出( Esc)27数字小键盘9105
上翻页( Page Up)33数字小键盘+107
下翻页( Page Down)34数字小键盘及大键盘上的-109
结尾( End)35数字小键盘.
开头( Home)36数字小键盘111
左箭头( Left Arrow)37F1112
上箭头( Up Arrow)38F2113
右箭头( Right Arrow)39F3114
下箭头( Down Arrow)40F4115
插入( Ins)45F5116
删除( Del)46F6117
左Windows键91F7118
右Windows键92F8119
上下文菜单键93F9120
数字小键盘096F10121
F11122 正斜杠191
F12123 沉音符( `)192
数字锁( Num Lock)144 等于 61
滚动锁( Scroll Lock)145左方括号219
分号( IE/Safari/Chrome中)186反斜杠( \)220
分号( Opera/FF中)、 59右方括号221
小于188单引号222
大于190
  1. 字符编码
    发生 keypress 事件意味着按下的键会影响到屏幕中文本的显示。在所有浏览器中,按下能够插入或删除字符的键都会触发 keypress 事件;按下其他键能否触发此事件因浏览器而异
var EventUtil = {
    //省略的代码
    getCharCode: function(event){
        if (typeof event.charCode == "number"){
            return event.charCode;
        } else {
            return event.keyCode;
        }
    },
    //省略的代码
};
  1. DOM3 级变化
    尽管所有浏览器都实现了某种形式的键盘事件, DOM3 级事件还是做出了一些改变。比如, DOM3级事件中的键盘事件,不再包含 charCode 属性,而是包含两个新属性: key 和 char。
var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "keypress", function(event){
    event = EventUtil.getEvent(event);
    var identifier = event.key || event.keyIdentifier;
    if (identifier){
        alert(identifier);
}
});

由于存在跨浏览器问题,因此本书不推荐使用 key、 keyIdentifier 或 char。
DOM3 级事件还添加了一个名为 location 的属性,这是一个数值,表示按下了什么位置上的键:0 表示默认键盘, 1 表示左侧位置(例如左位的 Alt 键), 2 表示右侧位置(例如右侧的 Shift 键), 3 表示数字小键盘, 4 表示移动设备键盘(也就是虚拟键盘), 5 表示手柄(如任天堂 Wii 控制器)。

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);
}
});
  1. textInput 事件
    “DOM3 级事件”规范中引入了一个新事件,名叫 textInput。根据规范,当用户在可编辑区域中输入字符时,就会触发这个事件。这个用于替代 keypress 的 textInput 事件的行为稍有不同。区别之一就是任何可以获得焦点的元素都可以触发 keypress 事件,但只有可编辑区域才能触发 textInput事件。区别之二是 textInput 事件只会在用户按下能够输入实际字符的键时才会被触发,而 keypress事件则在按下那些能够影响文本显示的键时也会触发(例如退格键)
var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "textInput", function(event){
    event = EventUtil.getEvent(event);
    alert(event.data);
});

另外, event 对象上还有一个属性,叫 inputMethod,表示把文本输入到文本框中的方式。

  • 0,表示浏览器不确定是怎么输入的。
  • 1,表示是使用键盘输入的。
  • 2,表示文本是粘贴进来的。
  • 3,表示文本是拖放进来的。
  • 4,表示文本是使用 IME 输入的。
  • 5,表示文本是通过在表单中选择某一项输入的。
  • 6,表示文本是通过手写输入的(比如使用手写笔)。
  • 7,表示文本是通过语音输入的。
  • 8,表示文本是通过几种方法组合输入的。
  • 9,表示文本是通过脚本输入的。
13.4.5 复合事件

复合事件( composition event)是 DOM3 级事件中新添加的一类事件,用于处理 IME 的输入序列。IME( Input Method Editor,输入法编辑器)可以让用户输入在物理键盘上找不到的字符。

  • compositionstart:在 IME 的文本复合系统打开时触发,表示要开始输入了。
  • compositionupdate:在向输入字段中插入新字符时触发。
  • compositionend:在 IME 的文本复合系统关闭时触发,表示返回正常键盘输入状态。复合事件与文本事件在很多方面都很相似。在触发复合事件时,目标是接收文本的输入字段。但它比文本事件的事件对象多一个属性 data,其中包含以下几个值中的一个:
  • 如果在 compositionstart 事件发生时访问,包含正在编辑的文本(例如,已经选中的需要马上替换的文本);
  • 如果在 compositionupdate 事件发生时访问,包含正插入的新字符;
  • 如果在 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);
});
13.4.6 变动事件

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

  • DOMSubtreeModified:在 DOM 结构中发生任何变化时触发。这个事件在其他任何事件触发后都会触发。
  • DOMNodeInserted:在一个节点作为子节点被插入到另一个节点中时触发。
  • DOMNodeRemoved:在节点从其父节点中被移除时触发。
  • DOMNodeInsertedIntoDocument:在一个节点被直接插入文档或通过子树间接插入文档之后触发。这个事件在 DOMNodeInserted 之后触发。
  • DOMNodeRemovedFromDocument:在一个节点被直接从文档中移除或通过子树间接从文档中移除之前触发。这个事件在 DOMNodeRemoved 之后触发。
  • DOMAttrModified:在特性被修改之后触发。
  • DOMCharacterDataModified:在文本节点的值发生变化时触发。
    使用下列代码可以检测出浏览器是否支持变动事件:
var isSupported = document.implementation.hasFeature("MutationEvents", "2.0");
  1. 删除节点
    在使用removeChild()或replaceChild()从 DOM中删除节点时,首先会触发DOMNodeRemoved事件。这个事件的目标( event.target)是被删除的节点,而 event.relatedNode 属性中包含着对目标节点父节点的引用。在这个事件触发时,节点尚未从其父节点删除,因此其 parentNode 属性仍然指向父节点(与 event.relatedNode 相同)。这个事件会冒泡,因而可以在 DOM 的任何层次上面处理它
<! DOCTYPE html>
<html>
<head>
    <title>Node Removal Events Example</title>
</head>
<body>
    <ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
</body>
</html>
EventUtil.addHandler(window, "load", function(event){
    var list = document.getElementById("myList");
EventUtil.addHandler(document, "DOMSubtreeModified", function(event){
    alert(event.type);
    alert(event.target);
});
EventUtil.addHandler(document, "DOMNodeRemoved", function(event){
    alert(event.type);
    alert(event.target);
    alert(event.relatedNode);
});
EventUtil.addHandler(list.firstChild, "DOMNodeRemovedFromDocument", function(event){
    alert(event.type);
    alert(event.target);
});
    list.parentNode.removeChild(list);
});
  1. 插入节点
    在使用 appendChild()、 replaceChild()或 insertBefore()向 DOM 中插入节点时,首先会触发 DOMNodeInserted 事件。这个事件的目标是被插入的节点,而 event.relatedNode 属性中包含一个对父节点的引用。在这个事件触发时,节点已经被插入到了新的父节点中。这个事件是冒泡的,因此可以在 DOM 的各个层次上处理它。
    1.DOMNodeInsertedIntoDocument
    2.DOMSubtreeModified
EventUtil.addHandler(window, "load", function(event){
    var list = document.getElementById("myList");
    var item = document.createElement("li");
    item.appendChild(document.createTextNode("Item 4"));
    EventUtil.addHandler(document, "DOMSubtreeModified", function(event){
        alert(event.type);
        alert(event.target);
    });
    EventUtil.addHandler(document, "DOMNodeInserted", function(event){
        alert(event.type);
        alert(event.target);
        alert(event.relatedNode);
    });
    EventUtil.addHandler(item, "DOMNodeInsertedIntoDocument", function(event){
        alert(event.type);
        alert(event.target);
    });
        list.appendChild(item);
});

以上代码首先创建了一个包含文本"Item4"的新<li>元素。由于DOMSubtreeModified和DOMNodeInserted事件是冒泡的,所以把它们的事件处理程序添加到了文档中。在将列表项插入到其父节点之前,先将DOMNodeInsertedIntoDocument事件的事件处理程序添加给它。最后一步就是使用appendChild()来添加这个列表项;此时,事件开始依次被触发。首先是在新<li>元素上触发DOMNodeInserted事件,其relatedNode是<ul>元素。然后是触发新<li>元素上的DOMNodeInsertedIntoDocument事件,最后触发的是<ul>元素上的DOMSubtreeModified事件。

13.4.7 HTML5 事件

DOM 规范没有涵盖所有浏览器支持的所有事件。很多浏览器出于不同的目的——满足用户需求或解决特殊问题,还实现了一些自定义的事件。 HTML5 详尽列出了浏览器应该支持的所有事件。本节只讨论其中得到浏览器完善支持的事件,但并非全部事件。(其他事件会在本书其他章节讨论。)

  1. contextmenu 事件
    contextmenu 这个事件,用以表示何时应该显示上下文菜单,以便开发人员取消默认的上下文菜单而提供自定义的菜单。
<!DOCTYPE html>
<html>
<head>
   <title>ContextMenu Event Example</title>
</head>
<body>
   <div id="myDiv">Right click or Ctrl+click me to get a custom context menu.Click anywhere else to get the default context menu.</div>
   <ul id="myMenu" style="position:absolute;visibility:hidden;background-color:silver">
       <li><a href="http://www.nczonline.net">Nicholas’ site</a></li>
       <li><a href="http://www.wrox.com">Wrox site</a></li>
       <li><a href="http://www.yahoo.com">Yahoo!</a></li>
   </ul>
</body>
</html>

这里的<div>元素包含一个自定义的上下文菜单。其中,<ul>元素作为自定义上下文菜单,并且在初始时是隐藏的。实现这个例子的 JavaScript 代码如下所示。

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

为<div>元素添加了 oncontextmenu 事件的处理程序。这个事件处理程序首先会取消默认行为,以保证不显示浏览器默认的上下文菜单。然后,再根据 event 对象 clientX 和clientY 属性的值,来确定放置<ul>元素的位置。最后一步就是通过将 visibility 属性设置为"visible"来显示自定义上下文菜单。另外,还为 document 添加了一个 onclick 事件处理程序,以便用户能够通过鼠标单击来隐藏菜单(单击也是隐藏系统上下文菜单的默认操作)。
2. beforeunload 事件
之所以有发生在 window 对象上的 beforeunload 事件,是为了让开发人员有可能在页面卸载前阻止这一操作。这个事件会在浏览器卸载页面之前触发,可以通过它来取消卸载并继续使用原有页面。但是,不能彻底取消这个事件,因为那就相当于让用户无法离开当前页面了。

EventUtil.addHandler("window","beforeunloaded",function(event){
    event = EventUtil.getEvent(event);
    var message = "I'm really going to miss you if you go";
    event.returnValue = message;
    return message;
})
  1. DOMContentLoaded 事件
    DOMContentLoaded 事件则在形成完整的 DOM 树之后就会触发,不理会图像、 JavaScript 文件、 CSS 文件或其他资源是否已经下载完毕。与 load 事件不同,DOMContentLoaded 支持在页面下载的早期添加事件处理程序,这也就意味着用户能够尽早地与页面进行交互。
EventUtil.addHandler(document,"DOMOontentLoaded",function(event){
    alert("Content Loaded")
});
  1. readystatechange 事件
    IE 为 DOM 文档中的某些部分提供了 readystatechange 事件。这个事件的目的是提供与文档或元素的加载状态有关的信息
  • uninitialized(未初始化):对象存在但尚未初始化。
  • loading(正在加载):对象正在加载数据。
  • loaded(加载完毕):对象加载数据完成。
  • interactive(交互):可以操作对象了,但还没有完全加载。
  • complete(完成):对象已经加载完毕。
EventUtil.addHandler(document,"readystatechange",funtion(event){
    if(document.readyState == "interactive"){
        alert("content loaded")
    }
});
  1. pageshow 和 pagehide 事件
    Firefox 和 Opera 有一个特性,名叫“往返缓存”( back-forward cache,或 bfcache),可以在用户使用浏览器的“后退”和“前进”按钮时加快页面的转换速度。
    第一个事件就是 pageshow,这个事件在页面显示时触发,无论该页面是否来自 bfcache。在重新加载的页面中, pageshow 会在 load 事件触发后触发;而对于 bfcache 中的页面, pageshow 会在页面状态完全恢复的那一刻触发。另外要注意的是,虽然这个事件的目标是 document,但必须将其事件处理程序添加到 window。
(function(){
    var showCount = 0;
    EventUtil.addHandler(window,"load",function(){
        alert("Load fired");
    });
    EventUtil.addHandler(window,"pageshow",function(){
        showcount++;
        alert("show has been fired"+ showCount+"times");
        //persistent属性
        alert("times,persistent"+event.persisted);
    })
})();
  1. hashchange 事件
    HTML5 新增了 hashchange 事件,以便在 URL 的参数列表(及 URL 中“#”号后面的所有字符串)发生变化时通知开发人员。之所以新增这个事件,是因为在 Ajax 应用中,开发人员经常要利用 URL 参数列表来保存状态或导航信息。
EventUtil.addHandler(window, "hashchange", function(event){
    alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL);
});
13.4.8 设备事件
  1. orientationchange 事件
    苹果公司为移动 Safari 中添加了 orientationchange 事件,以便开发人员能够确定用户何时将设备由横向查看模式切换为纵向查看模式。
    0 表示肖像模式, 90 表示向左旋转的横向模式(“主屏幕”按钮在右侧), -90 表示向右旋转的横向模式(“主屏幕”按钮在左侧)。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EbJX8Mxb-1579591369556)(/images/frontend-JavaScript-event-device-orientation.jpg)]
EventUtil.addHandler(window,"loaded",function(event){
    var div = document.getElementById("myDiv");
    div.innerHTML = "current orientation is"+window.orientation;
    EventUtil.addHandler(window, "orientationchange", function(event){
        div.innerHTML = "Current orientation is " + window.orientation;
    });
})
  1. MozOrientation 事件
    Firefox 3.6 为检测设备的方向引入了一个名为 MozOrientation 的新事件。(前缀 Moz 表示这是特定于浏览器开发商的事件,不是标准事件。)
EventUtil.addHandler(window, "MozOrientation", function(event){
//响应事件
});

此时的 event 对象包含三个属性: x、 y 和 z。这几个属性的值都介于 1 到-1 之间,表示不同坐标轴上的方向。在静止状态下, x 值为 0, y 值为 0, z 值为 1(表示设备处于竖直状态)。如果设备向右倾斜, x 值会减小;反之,向左倾斜, x 值会增大。类似地,如果设备向远离用户的方向倾斜, y 值会减小,向接近用户的方向倾斜, y 值会增大。z 轴检测垂直加速度度,1 表示静止不动,在设备移动时值会减小。(失重状态下值为 0。)以下是输出这三个值的一个简单的例子。

EventUtil.addHandler(window, "MozOrientation", function(event){
    var output = document.getElementById("output");
    output.innerHTML = "X=" + event.x + ", Y=" + event.y + ", Z=" + event.z +"<br>";
});
  1. deviceorientation 事件
    deviceorientation 事件的意图是告诉开发人员设备在空间中朝向哪儿,而不是如何移动。
  • alpha:在围绕 z 轴旋转时(即左右旋转时), y 轴的度数差;是一个介于 0 到 360 之间的浮点数。
  • beta:在围绕 x 轴旋转时(即前后旋转时), z 轴的度数差;是一个介于180 到 180 之间的浮点数。
  • gamma:在围绕 y 轴旋转时(即扭转设备时), z 轴的度数差;是一个介于90 到 90 之间的浮点数。
  • absolute:布尔值,表示设备是否返回一个绝对值。
  • compassCalibrated:布尔值,表示设备的指南针是否校准过。
EventUtil.addHandler(window, "deviceorientation", function(event){
    var output = document.getElementById("output");
    output.innerHTML = "Alpha=" + event.alpha + ", Beta=" + event.beta +", Gamma=" + event.gamma + "<br>";
});
  1. devicemotion 事件
    DeviceOrientation Event 规范还定义了一个 devicemotion 事件。这个事件是要告诉开发人员设备什么时候移动,而不仅仅是设备方向如何改变。
    触发 devicemotion 事件时,事件对象包含以下属性。
  • acceleration:一个包含 x、 y 和 z 属性的对象,在不考虑重力的情况下,告诉你在每个方上的加速度。
  • accelerationIncludingGravity:一个包含 x、 y 和 z 属性的对象,在考虑 z 轴自然重力加速度的情况下,告诉你在每个方向上的加速度。
  • interval:以毫秒表示的时间值,必须在另一个 devicemotion 事件触发前传入。这个值在每个事件中应该是一个常量
  • rotationRate:一个包含表示方向的 alpha、 beta 和 gamma 属性的对象。
EventUtil.addHandler(window, "devicemotion", function(event){
    var output = document.getElementById("output");
    if (event.rotationRate !== null){
        output.innerHTML += "Alpha=" + event.rotationRate.alpha + ", Beta=" +event.rotationRate.beta + ", Gamma=" +event.rotationRate.gamma;
    }
});
13.4.9 触摸与手势事件
  1. 触摸事件
  • touchstart:当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。
  • touchmove: 当手指在屏幕上滑动时连续地触发。在这个事件发生期间,调用 preventDefault()可以阻止滚动。
  • touchend:当手指从屏幕上移开时触发。
  • touchcancel:当系统停止跟踪触摸时触发。关于此事件的确切触发时间,文档中没有明确说明。
    上面这几个事件都会冒泡,也都可以取消。每个触摸事件的 event 对象都提供了在鼠标事件中常见的属性:bubbles、 cancelable、 view、 clientX、 clientY、 screenX、 screenY、 detail、 altKey、 shiftKey、ctrlKey 和 metaKey。
    除了常见的 DOM 属性外,触摸事件还包含下列三个用于跟踪触摸的属性。
  • touches:表示当前跟踪的触摸操作的 Touch 对象的数组。
  • targetTouchs:特定于事件目标的 Touch 对象的数组。
  • changeTouches:表示自上次触摸以来发生了什么改变的 Touch 对象的数组。每个 Touch 对象包含下列属性。
  • clientX:触摸目标在视口中的 x 坐标。
  • clientY:触摸目标在视口中的 y 坐标。
  • identifier:标识触摸的唯一 ID。
  • pageX:触摸目标在页面中的 x 坐标。
  • pageY:触摸目标在页面中的 y 坐标。
  • screenX:触摸目标在屏幕中的 x 坐标。
  • screenY:触摸目标在屏幕中的 y 坐标。
  • target:触摸的 DOM 节点目标。
function handleTouchEvent(event){
    //只跟踪一次触摸
    if (event.touches.length == 1){
        var output = document.getElementById("output");
        switch(event.type){
        case "touchstart":
        output.innerHTML = "Touch started (" + event.touches[0].clientX +"," + event.touches[0].clientY + ")";
        break;
        case "touchend":
        output.innerHTML += "<br>Touch ended (" +event.changedTouches[0].clientX + "," + event.changedTouches[0].clientY + ")";
        break;
        case "touchmove":
        event.preventDefault(); //阻止滚动
        output.innerHTML += "<br>Touch moved (" +event.changedTouches[0].clientX + "," + event.changedTouches[0].clientY + ")";
        break;
        }
    }
}
EventUtil.addHandler(document, "touchstart", handleTouchEvent);
EventUtil.addHandler(document, "touchend", handleTouchEvent);
EventUtil.addHandler(document, "touchmove", handleTouchEvent);
  1. 手势事件
    iOS 2.0 中的 Safari 还引入了一组手势事件。当两个手指触摸屏幕时就会产生手势,手势通常会改变显示项的大小,或者旋转显示项。有三个手势事件,分别介绍如下。
  • gesturestart:当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发。
  • gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发。
  • gestureend:当任何一个手指从屏幕上面移开时触发
function handleGestureEvent(event){
var output = document.getElementById("output");
    switch(event.type){
    case "gesturestart":
        output.innerHTML = "Gesture started (rotation=" + event.rotation +",scale=" + event.scale + ")";
    break;
    case "gestureend":
        output.innerHTML += "<br>Gesture ended (rotation=" + event.rotation +",scale=" + event.scale + ")";
    break;
    case "gesturechange":
        output.innerHTML += "<br>Gesture changed (rotation=" + event.rotation +",scale=" + event.scale + ")";
    break;
    }
}
document.addEventListener("gesturestart", handleGestureEvent, false);
document.addEventListener("gestureend", handleGestureEvent, false);
document.addEventListener("gesturechange", handleGestureEvent, false);

触摸事件也会返回 rotation 和 scale 属性,但这两个属性只会在两个手指与屏幕保持接触时才会发生变化。一般来说,使用基于两个手指的手势事件,要比管理触摸事件中的所有交互要容易得多

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 item1 = document.getElementById("goSomewhere");
var item2 = document.getElementById("doSomething");
var item3 = document.getElementById("sayHi");
EventUtil.addHandler(item1, "click", function(event){
    location.href = "http://www.wrox.com";
});
EventUtil.addHandler(item2, "click", function(event){
    document.title = "I changed the document's title";
});
EventUtil.addHandler(item3, "click", function(event){
    alert("hi");
});

添加事件委托:

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.5.2 移除事件处理程序

每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的 JavaScript 代码之间就会建立一个连接。这种连接越多,页面执行起来就越慢。

<div id="myDiv">
<input type="button" value="Click Me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(){
    //先执行某些操作
    btn.onclick = null; //移除事件处理程序
    document.getElementById("myDiv").innerHTML = "Processing...";
};
</script>

13.6 模拟事件

13.6.1 DOM中的事件模拟

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

  • UIEvents:一般化的 UI 事件。 鼠标事件和键盘事件都继承自 UI 事件。 DOM3 级中是 UIEvent。
  • MouseEvents:一般化的鼠标事件。 DOM3 级中是 MouseEvent。
  • MutationEvents:一般化的 DOM 变动事件。 DOM3 级中是 MutationEvent。
  • HTMLEvents:一般化的 HTML 事件。没有对应的 DOM3 级事件( HTML 事件被分散到其他类别中)。
  1. 模拟鼠标事件
    创建新的鼠标事件对象并为其指定必要的信息,就可以模拟鼠标事件。创建鼠标事件对象的方法是为 createEvent()传入字符串"MouseEvents"。返回的对象有一个名为 initMouseEvent()方法,用于指定与该鼠标事件有关的信息。
  • type(字符串):表示要触发的事件类型,例如"click"。
  • bubbles(布尔值):表示事件是否应该冒泡。为精确地模拟鼠标事件,应该把这个参数设置为true。
  • cancelable(布尔值):表示事件是否可以取消。为精确地模拟鼠标事件,应该把这个参数设置为 true。
  • view( AbstractView):与事件关联的视图。这个参数几乎总是要设置为 document.defaultView。
  • detail(整数): 与事件有关的详细信息。这个值一般只有事件处理程序使用,但通常都设置为 0。
  • screenX(整数):事件相对于屏幕的 X 坐标。
  • screenY(整数):事件相对于屏幕的 Y 坐标。
  • clientX(整数):事件相对于视口的 X 坐标。
  • clientY(整数):事件想对于视口的 Y 坐标。
  • ctrlKey(布尔值):表示是否按下了 Ctrl 键。默认值为 false。
  • altKey(布尔值):表示是否按下了 Alt 键。默认值为 false。
  • shiftKey(布尔值):表示是否按下了 Shift 键。默认值为 false。
  • metaKey(布尔值):表示是否按下了 Meta 键。默认值为 false。
  • button(整数):表示按下了哪一个鼠标键。默认值为 0。
  • 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);
  1. 模拟键盘事件
    DOM3 级规定,调用 createEvent()并传入"KeyboardEvent"就可以创建一个键盘事件。返回的事件对象会包含一个 initKeyEvent()方法,这个方法接收下列参数。
  • type(字符串):表示要触发的事件类型,如"keydown"。
  • bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为 true。
  • cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为 true。
  • view ( AbstractView ):与事件关联的视图。这个参数几乎总是要设置为 document.defaultView。
  • key(布尔值):表示按下的键的键码。
  • location(整数):表示按下了哪里的键。 0 表示默认的主键盘, 1 表示左, 2 表示右, 3 表示数字键盘, 4 表示移动设备(即虚拟键盘), 5 表示手柄。
  • modifiers(字符串):空格分隔的修改键列表,如"Shift"。
  • repeat(整数):在一行中按了这个键多少次。
    由于 DOM3 级不提倡使用 keypress 事件,因此只能利用这种技术来模拟 keydown 和 keyup 事件。
var textbox = document.getElementById("myTextbox"),
    event;
//以 DOM3 级方式创建事件对象
if (document.implementation.hasFeature("KeyboardEvents", "3.0")){
    event = document.createEvent("KeyboardEvent");
    //初始化事件对象
    event.initKeyboardEvent("keydown", true, true, document.defaultView, "a",0, "Shift", 0);
}
//触发事件
textbox.dispatchEvent(event);
//通用键盘事件
var textbox = document.getElementById("myTextbox");
//创建事件对象
var event = document.createEvent("Events");
//初始化事件对象
event.initEvent(type, bubbles, cancelable);
event.view = document.defaultView;
event.altKey = false;
event.ctrlKey = false;
event.shiftKey = false;
event.metaKey = false;
event.keyCode = 65;
event.charCode = 65;
//触发事件
textbox.dispatchEvent(event);
  1. 模拟其他事件
    虽然鼠标事件和键盘事件是在浏览器中最经常模拟的事件,但有时候同样需要模拟变动事件和HTML 事 件 。 要模拟变动事件 , 可以使用 createEvent(“MutationEvents”) 创建一个包含initMutationEvent()方法的变动事件对象 。 这个方法接受的参数包括 :type、bubbles 、
    cancelable、 relatedNode、 preValue、 newValue、 attrName 和 attrChange。
var event = document.createEvent("MutationEvents");
event.initMutationEvent("DOMNodeInserted", true, false, someNode, "","","",0);
target.dispatchEvent(event);
  1. 自定义 DOM 事件
    DOM3 级还定义了“自定义事件”。自定义事件不是由 DOM 原生触发的,它的目的是让开发人员创建自己的事件。要创建新的自定义事件,可以调用 createEvent(“CustomEvent”)。返回的对象有一个名为 initCustomEvent()的方法,接收如下 4 个参数。
  • type(字符串):触发的事件类型,例如"keydown"。
  • bubbles(布尔值):表示事件是否应该冒泡。
  • cancelable(布尔值):表示事件是否可以取消。
  • detail(对象):任意值,保存在 event 对象的 detail 属性中
var div = document.getElementById("myDiv"),
    event;
EventUtil.addHandler(div, "myevent", function(event){
    alert("DIV: " + event.detail);
});
EventUtil.addHandler(document, "myevent", function(event){
    alert("DOCUMENT: " + event.detail);
});
if (document.implementation.hasFeature("CustomEvents", "3.0")){
    event = document.createEvent("CustomEvent");
    event.initCustomEvent("myevent", true, false, "Hello world!");
    div.dispatchEvent(event);
}
13.6.2 IE中的事件模拟

调用 document.createEventObject()方法可以在 IE 中创建 event 对象。但与 DOM 方式不同的是,这个方法不接受参数,结果会返回一个通用的 event 对象。

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);
//采用相同的模式也可以模拟触发 keypress 事件,如下面的例子所示。
var textbox = document.getElementById("myTextbox");
//创建事件对象
var event = document.createEventObject();
//初始化事件对象
event.altKey = false;
event.ctrlKey = false;
event.shiftKey = false;
event.keyCode = 65;
//触发事件
textbox.fireEvent("onkeypress", event);

13.7 小结

事件是将 JavaScript 与网页联系在一起的主要方式。“DOM3 级事件”规范和 HTML5 定义了常见的大多数事件。即使有规范定义了基本事件,但很多浏览器仍然在规范之外实现了自己的专有事件,从而为开发人员提供更多掌握用户交互的手段。
在使用事件时,需要考虑如下一些内存与性能方面的问题。

  • 有必要限制一个页面中事件处理程序的数量,数量太多会导致占用大量内存,而且也会让用户感觉页面反应不够灵敏。
  • 建立在事件冒泡机制之上的事件委托技术,可以有效地减少事件处理程序的数量。
  • 建议在浏览器卸载页面之前移除页面中的所有事件处理程序。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值