理解JavaScript事件以及事件处理程序——笔记整理

来源:互联网 发布:it技术论坛排行榜 编辑:程序博客网 时间:2024/06/07 06:22

摘要

  JavaScript与HTML之间的交互是通过事件来实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用侦听器(或处理程序)来预定事件,以便事件发生时执行相应的代码。

事件流

  事件流描述的是从页面中接收事件的顺序,“DOM2级事件”规定事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。
  这里们对事件冒泡和事件捕获做一个详细的描述。看下面的HTML代码:

<!DOCTYPE html><html><head>    <title>事件描述</title></head><body>    <div id="div1">点击我</div></body></html>

事件冒泡

  事件冒泡,即时间开始时由具体的元素接受,然后逐级向上传播到较为不具体的节点。
  如果单击了页面中的< div>元素,那么这个click事件就会按照如下顺序传播:
  (1)div
  (2)body
  (3)html
  (4)document

事件捕获

  事件捕获,事件捕获的思想反之,就是从不太具体的节点最先接受到事件,而最具体的节点应该最后接收到事件。

DOM事件流

  “DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。其中处于目标阶段被看成冒泡阶段的一部分,事件由文档向下传播,又传播回文档。

事件处理程序

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

HTML事件处理程序(已不推荐使用)

  看下面HTML代码:

<input type="button" value="Click Me" onclick="alert('Clicked!')" /><input type="button" value="Click Me" onclick="showMsg()" /><script>    function showMsg(){        alert("Clicked!");    }</script>

以上两种方式均是HTML事件处理程序的表现,第一种将js代码写进了input标签里面,第二种则是调用了script标签里的函数,这里所使用的html事件处理程序,违背了结构呈与交互层分离的原则,故不推荐使用。

DOM0级事件处理程序

  通过js指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。具有简单和跨浏览器的优势。

var button=document.getElementById("myButton");button.onclick=function(){    alert('Clicked!'+this.id);};

  DOM0级方法指定的事件处理程序被认为是元素的方法。因此,这里的处理程序实在元素的作用域中运行的;程序中的this引用的是当前元素。

DOM2级事件处理程序

  “DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()removeEventListener()。所有的DOM节点中都可以包含这两个方法。这两个方法都接收三个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后的布尔值如果是true,表示在捕获事件阶段调用处理程序;如果是false,表示在冒泡阶段调用。

var btn=document.getElementById("myButton");btn.addEventListener("click",function(){    alert(this.id);),false);

  通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除;移除时传入的参数与添加处理程序时使用的参数相同。所以通过addEventListener()添加的匿名函数将无法移除。所以在添加函数时需要给函数命名:

var btn=document.getElementById("myButton");var fn=function(){    alert(this.id);}btn.addEventListener("click",fn,false);btn.removeEventListener("click",fn,false);

事件对象event

  在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。例如,鼠标操作导致的事件对象中,会包含鼠标位置的信息,而键盘操作导致的事件对象中,会包含按下的键有关的信息。

DOM中的事件对象

  下面的代码详细表述了event对象中的type和target属性,如果直接将事件处理程序指定给了目标元素,则 this、currentTarget和target包含相同的值。

var btn=document.getElementById("myButton");var fn=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=fn;btn.onmouseover=fn;btn.onmouseout=fn;

  这个例子中定义了一个名为fn的函数,用于处理三种事件:click、mouseover和mouseout。当单击按钮时,会出现一个提示框;当鼠标移动到按钮上时,背景色会变成红色;当鼠标从按钮上移出时,背景色会恢复默认。这里通过检测event.type属性,让函数能够确定发生了什么行为,以便执行相应的操作。

event.preventDefault(); //阻止特定事件的默认行为
event.stopPropagation(); //立即停止事件在DOM层次中传播(捕获或者冒泡)

  只有在事件处理程序执行期间,event对象才会存在;一旦事件处理程序执行完成,event对象就会被销毁。

跨浏览器事件对象

  这里有一段跨浏览器事件的js:

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;        }    },    getButton: function(event){ //鼠标事件button值        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;            }        }    },    getCharCode: function(event){ //键盘值        if (typeof event.charCode == "number"){            return event.charCode;        } else {            return event.keyCode;        }    },    getClipboardText: function(event){ //触控板        var clipboardData =  (event.clipboardData || window.clipboardData);        return clipboardData.getData("text");    },    getEvent: function(event){  //得到事件对象event        return event ? event : window.event;    },    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;        }    },    getTarget: function(event){        return event.target || event.srcElement;    },    getWheelDelta: function(event){        if (event.wheelDelta){            return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta);        } else {            return -event.detail * 40;        }    },    preventDefault: function(event){        if (event.preventDefault){            event.preventDefault();        } else {            event.returnValue = false;        }    },    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;        }    },     setClipboardText: function(event, value){        if (event.clipboardData){            event.clipboardData.setData("text/plain", value);        } else if (window.clipboardData){            window.clipboardData.setData("text", value);        }    },    stopPropagation: function(event){        if (event.stopPropagation){            event.stopPropagation();        } else {            event.cancelBubble = true;        }    }};

上面的js代码能解决大部分跨浏览器事件。

内存和性能

  虽然事件处理程序可以为现代web应用提供强大的交互能力,但是添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能。首先,每个函数都是对象,都会占用内存;内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪事件。事实上,从如何利用好事件处理程序的角度出发,还是有一些方法能够提升性能的。

事件委托

  对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。以下面的HTML代码为例:

<ul id="mylinks">    <li id="gotoBaidu">Viste Baidu</li>    <li id="dosth">Change Title</li>    <li id="sayHello">Say Hello</li></ul>

  使用事件委托,只需要在DOM树中尽量高的层次上添加一个事件处理程序,如下面的例子:

var list = document.getElementById("mylinks");EventUtil.addHandler(list,"click",function(event){    event = EventUtil.getEvent(event);    var target = EventUtil.getTarget(event);    switch(target.id){        case "dosth":            document.title="I changed the document's title";            break;        case "gotoBaidu":            location.href="https://www.baidu.com/";            break;        case "sayHello":            alert("Hello!");            break;    }});

  在这段代码里,我们使用事件委托只为ul元素添加了一个onclick事件处理程序。由于所有列表项都是这个元素的子节点,而他们的事件会冒泡,所以单机事件最终会被这个函数处理。这种技术需要占用的内存更少。

移除事件处理程序

  每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的Javascript代码之间就会建立一个连接。这种连接越多,页面执行起来就越慢 。在不需要的时候移除事件处理程序,也是解决这个问题的一种方案。内存中留有那些过时不用的“空事件处理程序”,也是造成web应用程序内存与性能问题的主要原因。

btn.onclick=function(){    //先执行某些操作    btn.onclick = null;  //移除事件处理程序};
0 0
原创粉丝点击