【javascript】事件-内存性能&模拟事件
2017-12-15 本文已影响0人
shanruopeng
内存和性能
- 在JavaScript 中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能。
- 导致这一问题的原因是多方面的。
- 每个函数都是对象,都会占用内存;内存中的对象越多,性能就越差。
- 必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。
//事件处理程序,方便后面使用
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;
}
},
getEvent: function(event){
return event ? event : window.event;
},
getTarget: function(event){
return event.target || event.srcElement;
},
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;
}
}
};
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;
}
});
- 这样使用事件委托与采取传统的做法相比具有如下优点。
- document 对象很快就可以访问,而且可以在页面生命周期的任何时点上为它添加事件处理程序(无需等待DOMContentLoaded或load事件)。换句话说,只要可单击的元素呈现在页面上,就可以立即具备适当的功能。
- 在页面中设置事件处理程序所需的时间更少。只添加一个事件处理程序所需的DOM 引用更少,所花的时间也更少。
- 整个页面占用的内存空间更少,能够提升整体性能。
- 最适合采用事件委托技术的事件包括click、mousedown、mouseup、keydown、keyup 和keypress。
2、移除事件处理程序
- 每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的JavaScript 代码之间就会建立一个连接。这种连接越多,页面执行起来就越慢。
- 在不需要的时候移除事件处理程序,也是解决这个问题的一种方案。
- 在两种情况下,可能会造成导致“空事件处理程序”。
- 从文档中移除带有事件处理程序的元素时。更多地是发生在使用innerHTML替换页面中某一部分的时候。如果带有事件处理程序的元素被innerHTML删除了,那么原来添加到元素中的事件处理程序极有可能无法被当作垃圾回收。
<div id="myDiv">
<input type="button" value="Click Me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(){
//先执行某些操作
document.getElementById("myDiv").innerHTML = "Processing..."; //麻烦了!
};
</script>
<!--- 如果你知道某个元素即将被移除,那么最好手工移除事件处理程序。-->
<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>
- 另一种情况,就是卸载页面的时候。如果在页面被卸载之前没有清理干净事件处理程序,那它们就会滞留在内存中。可以在页面卸载之前,先通过onunload事件处理程序移除所有事件处理程序,
- 注意,使用onunload 事件处理程序意味着页面不会被缓存在bfcache 中。
模拟事件
- 可以使用JavaScript 在任意时刻来触发特定的事件,而此时的事件就如同浏览器创
建的事件一样。
1、DOM中的事件模拟
- 可以在document 对象上使用createEvent()方法创建event对象。这个方法接收一个参数,即表示要创建的事件类型的字符串。
事件名称 | 解释 |
---|---|
UIEvents | 一般化的UI 事件。鼠标事件和键盘事件都继承自UI 事件 |
MouseEvents | 一般化的鼠标事件 |
MutationEvents | 一般化的DOM 变动事件 |
HTMLEvents | 一般化的HTML 事件 |
- 在创建了event 对象之后,还需要使用与事件有关的信息对其进行初始化。
- 每种类型的event 对象都有一个特殊的方法,为它传入适当的数据就可以初始化该event 对象。不同类型的这个方法的名字也不相同,具体要取决于createEvent()中使用的参数。
- 模拟事件的最后一步就是触发事件,使用dispatchEvent()方法,需要传入一个参数,即表示要触发事件的event 对象。
(1)模拟鼠标事件
- 创建新的鼠标事件对象并为其指定必要的信息,就可以模拟鼠标事件。
- 创建鼠标事件对象的方法是为createEvent()传入字符串"MouseEvents"。返回的对象有一个名为initMouseEvent()方法,用于指定与该鼠标事件有关的信息。
- 这个方法接收15 个参数,分别与鼠标事件中每个典型的属性一一对应。
参数 | 含义 |
---|---|
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);
(2)模拟键盘事件
- 调用createEvent()并传入"KeyboardEvent"就可以创建一个键盘事件。返回的事件对象会包含一个initKeyEvent()方法,这个方法接收下列参数。
参数 | 含义 |
---|---|
type(字符串) | 表示要触发的事件类型,如"keydown"。 |
bubbles(布尔值) | 表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为true。 |
cancelable(布尔值) | 表示事件是否可以取消。为精确模拟鼠标事件,应该设置为true。 |
view | 与事件关联的视图。这个参数几乎总是要设置为document.defaultView。 |
key(布尔值) | 表示按下的键的键码。 |
location(整数) | 表示按下了哪里的键。0 表示默认的主键盘,1 表示左,2 表示右,3 表示数字键盘,4 表示移动设备(即虚拟键盘),5 表示手柄。 |
modifiers(字符串) | 空格分隔的修改键列表,如"Shift"。 |
repeat(整数) | 在一行中按了这个键多少次。 |
/**模拟按住Shift 的同时又按下A 键。**/
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);
(3)模拟其它事件
- 要模拟变动事件, 可以使用createEvent("MutationEvents")创建一个包含initMutationEvent() 方法的变动事件对象。
- 这个方法接受的参数包括:type、bubbles、cancelable、relatedNode、preValue、newValue、attrName 和attrChange。
var event = document.createEvent("MutationEvents");
event.initMutationEvent("DOMNodeInserted", true, false, someNode, "","","",0);
targ et.dispatchEvent(event);
- 模拟HTML 事件,同样需要先创建一个event对象——通过createEvent("HTMLEvents"),然后再使用这个对象的initEvent()方法来初始化它。
var event = document.createEvent("HTMLEvents");
event.initEvent("focus", true, false);
targ et.dispatchEvent(event);
(4)自定义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);
}
- 支持自定义DOM事件的浏览器有IE9+和Firefox 6+。
2、IE中的事件模拟
- 调用document.createEventObject()方法可以在IE中创建event对象,这个方法不接受参数,结果会返回一个通用的event 对象。
- 然后,你必须手工为这个对象添加所有必要的信息。
- 最后一步就是在目标上调用fireEvent()方法,这个方法接受两个参数:事件处理程序的名称和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);
好好学习