第十三章:事件(内存和性能、模拟事件)

来源:互联网 发布:黑客远控软件 编辑:程序博客网 时间:2024/06/05 18:39

事件

内存和性能

  • 前面我们提到了好多好多事件,那么为页面添加事件处理程序就设计到了内存和性能问题。例如,如果我们为大量按钮添加匿名函数事件处理程序,首先这些匿名函数都是对象是占用空间的,其次这些添加事件处理程序的操作也会延迟整个页面的交互就绪时间

事件委托

  • 由于大多数类型的事件都是会冒泡的,所以我们可以为它们相同的父元素添加一件事件处理程序,这样就能避免大量地添加事件处理程序了。不过这样会存在一个问题,就是子元素它们要执行的操作的差异问题。如果子元素执行的操作,差异不大,可以写成一个公共代码(例如取出当前节点value的值改变一个固定节点的value)。如果差异巨大,那么我们也可以通过switch语句进行区分(虽然代码行数可能没有变化,但是看起来清爽一点)。
  • 当然这么做好处也是很明显的,一是代码逻辑更好,二是我们指定了更少的事件处理程序,三是我们减少了DOM节点的获取(无须再获得子节点的引用)
<!DOCTYPE html><html><head>    <title>Event Delegation Example</title></head><body>    <ul id="myLinks">        <li id="goSomewhere">Go somewhere</li>        <li id="doSomething">Do something</li>        <li id="sayHi">Say hi</li>    </ul>    <script type="text/javascript">    (function(){        var list = document.getElementById("myLinks");        list.addEventListener("click", function(event){            switch(event.target.id){//event.target保存着触发事件的源节点                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;            }        });    })();    </script></body></html>

移除事件处理程序

  • 每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的JavaScript 代码之间就会建立一个连接。连接越多,页面自然越缓慢。除了通过事件委托减少连接,我们也可以移除无用的事件处理程序来减少连接数。
  • 那么问题来了,无用的事件处理程序是怎么来的呢?最常见的一种情况就是,我们为元素添加了事件处理程序,然后我们用innerHTML改变了父节点的内容,此时的事件处理程序无法得到正常回收(尤其是IE浏览器,有些浏览器可能能够准确处理),就成了无用的事件处理程序。
<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>
  • 采用事件委托也有助于解决这个问题。如果事先知道将来有可能使用innerHTML替换掉页面中的某一部分,那么就可以不直接把事件处理程序添加到该部分的元素中。而通过把事件处理程序指定给较高层次的元素,同样能够处理该区域中的事件。
  • 导致“空事件处理程序”的另一种情况,就是卸载页面的时候。毫不奇怪,IE8 及更早版本在这种情况下依然是问题最多的浏览器,尽管其他浏览器或多或少也有类似的问题。如果在页面被卸载之前没有清理干净事件处理程序,那它们就会滞留在内存中。每次加载完页面再卸载页面时(可能是在两个页面间来回切换,也可以是单击了“刷新”按钮),内存中滞留的对象数目就会增加,因为事件处理程序占用的内存并没有被释放。

模拟事件

  • 事件经常由用户操作或通过其他浏览器功能来触发。不过事件也可以使用JavaScript任意时刻来触发特定的事件,而此时的事件就如同浏览器创建的事件一样(我起初以为是click()触发click事件,但没有那么简单)。

DOM中的事件模拟

  • 可以在document 对象上使用createEvent()方法创建event 对象。这个方法接收一个参数,即表示要创建的事件类型的字符串。在DOM2级中这些字符串都是复数形式,在DOM3中都变成了单数。以下是DOM2级中的字符串:
    1. UIEvents:一般化的UI 事件。鼠标事件和键盘事件都继承自UI 事件。
    2. MouseEvents:一般化的鼠标事件。
    3. MutationEvents:一般化的DOM 变动事件。
    4. HTMLEvents:一般化的HTML 事件。没有对应的DOM3 级事件(HTML 事件被分散到其他类别中)。
  • 在创建了event 对象之后,还需要使用与事件有关的信息对其进行初始化。每种类型的event 对象都有一个特殊的方法,为它传入适当的数据就可以初始化该event 对象。
  • 初始化完毕后,就是触发事件了。这一步需要使用dispatchEvent()方法,所有支持事件的DOM 节点都支持这个方法。调用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(0表示主鼠标按钮(一般为左键),1表示中间按钮(滚轮),2表示次鼠标按钮(右键))。
    15. relatedTarget(对象):表示与事件相关的对象。这个参数只在模拟mouseovermouseout时使用。
<!DOCTYPE html><html><head>    <title>Simulating DOM Mouse Events Example</title></head><body>    <input type="button" value="Click me" id="myBtn" />    <input type="button" value="Send click to the other button" id="myBtn2" />    <p>This example works in DOM-compliant browsers (not IE8-).</p>    <script type="text/javascript">    (function(){        var btn = document.getElementById("myBtn");        var btn2 = document.getElementById("myBtn2");        btn.addEventListener("click", function(event){            alert("Clicked!");            alert(event.screenX);   //100        });        btn2.addEventListener("click", function(event){            //create event object            var event = document.createEvent("MouseEvents");            //initialize the event object            event.initMouseEvent("click", true, true, document.defaultView, 0, 100, 0, 0, 0, false,                                  false, false, false, 0, btn2);            //fire the event            btn.dispatchEvent(event);        });    })();    </script></body></html>

模拟键盘事件

  • DOM2 级事件”中没有就键盘事件作出规定,因此模拟键盘事件并没有现成的思路可循。DOM3 级规定,调用createEvent()并入”KeyboardEvent“就可以创建一个键盘事件。返回的事件对象会包含一个initKeyEvent()方法,这个方法接收下列参数:
    1. type(字符串):表示要触发的事件类型,如”keydown”。
    2. bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为true
    3. cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为true
    4. view (AbstractView ):与事件关联的视图。这个参数几乎总是要设置为document.defaultView
    5. key(布尔值):表示按下的键的键码
    6. location(整数):表示按下了哪里的键。0 表示默认的主键盘,1 表示左,2 表示右,3 表示数字键盘,4 表示移动设备(即虚拟键盘),5 表示手柄。
    7. modifiers(字符串):空格分隔的修改键列表,如”Shift”。
    8. repeat(整数):在一行中按了这个键多少次
  • 但这个方法好像已经过时,所以这里就不再说明了。
  • 由于DOM3级不提倡使用keypress 事件,因此只能利用这种技术来模拟keydown 和keyup 事件。
  • Firefox中,调用createEvent()并传入KeyEvents就可以创建一个键盘事件。返回的对象会包含一个initKeyEvent()方法,这个方法接收以下10个参数。
    1. type(字符串):表示要触发的事件类型,如”keydown”。
    2. bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为true。
    3. cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为true。
    4. view(AbstractView):与事件关联的视图。这个参数几乎总是要设置为document.default-View
    5. ctrlKey(布尔值):表示是否按下了Ctrl 键。默认值为false。
    6. altKey(布尔值):表示是否按下了Alt 键。默认值为false。
    7. shiftKey(布尔值):表示是否按下了Shift 键。默认值为false。
    8. metaKey(布尔值):表示是否按下了Meta 键。默认值为false。
    9. keyCode(整数):被按下或释放的键的键码。这个参数对keydown 和keyup 事件有用,默认值为0。
    10. charCode(整数):通过按键生成的字符的ASCII 编码。这个参数对keypress 事件有用,默认值为0。
  • 将创建的event对象传入到dispatchEvent()方法就可以触发键盘事件。
  • 在其他浏览器中,则需要创建一个通用的事件,然后向事件对象中添加键盘事件特有的信息。
<!DOCTYPE html><html><head>    <title>Simulating DOM Keyboard Events Example</title></head><body>    <input type="text" value="" id="myTextbox" />    <input type="button" value="Send keydown to the textbox" id="myBtn" />    <script type="text/javascript">    (function(){        var btn = document.getElementById("myBtn");        var textbox = document.getElementById("myTextbox");        textbox.addEventListener("keydown", function(event){            alert(event.type);            alert(event.keyCode);            event.target.value = String.fromCharCode(event.keyCode);            //去掉上面这段代码,没有出现A,说明模拟键盘事件,只会触发该事件事件处理程序,而不会造成原有的影响。        });        btn.addEventListener("click", function(event){            //create event object            var event;            try {                //Firefox implementation                event = document.createEvent("KeyEvents");                event.initKeyEvent("keydown", true, true, document.defaultView, false, false,                                    true, false, 65, 65);            } catch (ex){ //others                alert("No KeyEvents");                event = document.createEvent("Events");//通用事件                event.initEvent("keydown", true, true);                event.view = document.defaultView;                event.altKey = false;                event.ctrlKey = false;                event.shiftKey = false;                event.metaKey = false;                event.keyCode = 65;                event.charCode = 65;            }            //fire the event            textbox.dispatchEvent(event);        });    })();    </script></body></html>

模拟其他事件

  • 有时候需要模拟变动事件HTML 事件。要模拟变动事件, 可以使用createEvent(“MutationEvents“) 创建一个包含initMutationEvent() 方法的变动事件对象。这个方法接受的参数包括: type 、bubbles 、cancelable、relatedNode、preValue、newValue、attrName 和attrChange。
  • 模拟HTML 事件,同样需要先创建一个event 对象——通过createEvent(“HTMLEvents”),然后再使用这个对象的initEvent()方法来初始化它即可。
  • 因为极少使用,我就不做例子测试了(其实我试了下beforeunload不好用)。

自定义DOM 事件

  • DOM3 级还定义了“自定义事件”。自定义事件不是由DOM 原生触发的,它的目的是让开发人员创建自己的事件。要创建新的自定义事件,可以调用createEvent(“CustomEvent”)。返回的对象有一个名为initCustomEvent()的方法,接收如下4 个参数:
    1. type(字符串):触发的事件类型,例如”keydown”。
    2. bubbles
    3. cancelable
    4. detail(对象):任意值,保存在event 对象的detail 属性中。
<!DOCTYPE html><html><head>    <title>Simulating DOM Text Input Events Example</title></head><body>    <div id="myDiv"></div>    <input type="button" value="Send textInput to the textbox" id="myBtn" />    <script type="text/javascript">    (function(){        var btn = document.getElementById("myBtn");        var div = document.getElementById("myDiv");        div.addEventListener("myevent", function(event){           alert("DIV: " + event.detail);        });        document.addEventListener("myevent", function(event){           alert("DOCUMENT: " + event.detail);        });        btn.addEventListener("click", function(event){            var event;            if (document.implementation.hasFeature("CustomEvents", "3.0")){                event = document.createEvent("CustomEvent");                event.initCustomEvent("myevent", true, false, "Hello world!");                div.dispatchEvent(event);            }        });    })();    </script></body></html>
  • 点击按钮后会依次弹出DIV: Hello world!DOCUMENT: Hello world!

IE中的事件模拟

  • IE8 及之前版本中模拟事件与在DOM中模拟事件的思路相似:先创建event 对象,然后为其指定相应的信息,然后再使用该对象来触发事件。
  • 调用document.createEventObject()方法可以在IE 中创建event 对象。这个方法不接受参数,结果会返回一个通用的event 对象。然后,你必须手工为这个对象添加所有必要的信息。最后一步就是在目标上调fireEvent()方法,这个方法接受两个参数事件处理程序的名称event 对象。在调用fireEvent()方法时,会自动为event 对象添加srcElement 和type 属性;其他属性则都是必须通过手工添加的。下面的代码模拟了在一个按钮上触发click 事件过程。
<!DOCTYPE html><html><head>    <title>Simulating IE Mouse Events Example</title></head><body>    <input type="button" value="Click me" id="myBtn" />    <input type="button" value="Send click to the other button" id="myBtn2" />    <p>This example works only in Internet Explorer.</p>    <script type="text/javascript">    (function(){        var btn = document.getElementById("myBtn");        var btn2 = document.getElementById("myBtn2");        btn.attachEvent("onclick", function(event){            alert("Clicked!");            alert(event.screenX);   //100        });        btn2.attachEvent("onclick", function(event){            //create event object            var event = document.createEventObject();            //initialize the event object            event.view = window;            event.detail = 0;            event.screenX = 100;            event.screenY = 0;            event.clientX = 0;            event.clientY = 0;            event.ctrlKey = false;            event.altKey = false;            event.metaKey = false;            event.shiftKey = false;            event.button = 0;            event.relatedTarget = null;            //fire the event            btn.fireEvent("onclick", event);        });    })();    </script></body></html>
  • 下面的代码模拟触发keypress 事件。
<!DOCTYPE html><html><head>    <title>Simulating IE Keyboard Events Example</title></head><body>    <input type="text" value="" id="myTextbox" />    <input type="button" value="Send keypress to the textbox" id="myBtn" />    <p>This example works in IE though no text will appear in the textbox.</p>    <script type="text/javascript">    (function(){        var btn = document.getElementById("myBtn");        var textbox = document.getElementById("myTextbox");        textbox.attachEvent("onkeypress", function(event){            event = window.event;            alert(event.keyCode);            event.srcElement.value = String.fromCharCode(event.keyCode);            //去掉上面这段代码,没有出现A,说明模拟键盘事件,只会触发该事件事件处理程序,而不会造成原有的影响。        });        btn.attachEvent("onclick", function(event){            //create event object            var event = document.createEventObject();            //initialize the event object            event.altKey = false;            event.ctrlKey = false;            event.shiftKey = false;            event.keyCode = 65;            //fire the event            textbox.fireEvent("onkeypress", event);        });    })();    </script></body></html>
阅读全文
0 0
原创粉丝点击