通过指定事件处理程序可以侦听事件的发生并对其作出响应,已达到某种交互目的。那么指定事件处理程序的方式有哪些呢?
比如有以下代码:
<input id="btn" type="button" value="click me" />
要求为按钮指定一个单击事件处理程序,即单击按钮时输出相应信息。
1.HTML事件处理程序
某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定。特性的值可以是能够执行的js代码。
<input id="btn" value="click me" onclick="alert('clicked')" />
也可以调用在页面其他地方定义的脚本。
<script type="text/javascript">
function showMessage(){
alert("clicked");
} </script>
<input id="btn" value="click me" onclick="showMessage()" />
showMessage()这个函数可以向以上方式定义,也可以被包含在一个外部文件中。事件处理程序中的代码在执行时,有权访问全局作用域中的任何代码。
缺点:
- 时差问题:因为需要触发事件处理程序时条件不具备。解决方法是将HTML事件处理程序封装在一个try-catch块中,以便错误不浮出水面。
<input type="button" value="click me" onclick="try{showMessage();}catch(ex){}"/>
- 作用域链:由于不同浏览器的JavaScript引擎遵循的标识符解析规则裸游差异,可能会导致扩展事件处理程序的作用域链有不同结果。
- HTML与JavaScript代码紧密耦合:如果想要更换事件处理程序,需要同时修改两个地方。
2.DOM0级事件处理程序
通过JavaScript指定处理程序的传统方式,将一个函数赋值给一个事件处理程序属性。每个元素(包括document和window)都有自己的事件处理程序属性,这些属性通常全部小写,如onclick。
var btn = document.getElementById("btn"); //指定事件处理程序 btn.onclick = function(){ alert("Clicked"); }; //想要取消事件处理程序的话,只需将事件处理程序属性设为null即可 btn.onclick = null;
这种方式下指定的事件处理程序被认为是元素的方法,所以其作用域为元素的作用域。即程序中的this引用当前元素。如:
btn.οnclick=function(){ alert(this.id);//btn }
另外以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。
3.DOM2级事件处理程序
“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener()。所有的DOM节点都包含着两个方法,并且它们都接受三个参数:要处理的事件名、事件处理程序的函数和一个布尔值。其中布尔值为true表示在捕获阶段调用事件处理程序,为false表示在冒泡阶段调用事件处理程序。
//指定事件处理程序 btn.addEventListener("click",fucntion(){alert("clicked");},false); //取消事件处理程序 btn.removeEventListener("click",function(){alert("clicked");},false);//无效 //指定和取消的参数必须完全相同才有效。而匿名函数是两个不同的函数,所以无效 //所以为了能够取消,最好函数采用命名函数
var handler = function(){ alert("clicked"); }; //添加事件处理程序 btn.addEventListener("click",handler,false); //取消事件处理程序 btn.removeEventListener("click",handler,false);//有效
作用域与DOM0级事件指定事件处理程序的作用域相同,也是元素的作用域。但与DOM0不同的是,DOM2可以指定多个事件处理程序。
事件处理程序的触发顺序是按照添加事件处理程序的顺序来的。
支持DOM2级事件处理程序的浏览器有IE9+、Firefox、Safari、Chrome和Opera。
4.IE事件处理程序
IE实现了与DOM类似的两种方法:attachEvent()和detachEvent()。接受两个参数:事件处理程序名与事件处理程序函数。IE8-只支持事件冒泡,所以通过attachEvent()添加的事件处理程序被添加到事件冒泡阶段。
//添加事件处理程序 btn.attachEvent("onclick",handler); //取消事件处理程序 btn.detachEvent("onclick",handler); //取消参数必须与添加完全相同,所以事件处理程序函数(同DOM2级事件中的分析一样)不要是匿名函数。
IE事件处理程序与DOM事件处理程序的最大区别:DOM0/2级事件处理程序的作用域是元素作用域;而IE事件处理程序是全局作用域,即this等于widow。
IE也可以指定多个事件处理程序,我运行了相关代码发现:触发顺序同添加顺序(IE9);而《JavaScript高级程序设计》中说触发顺序应该同添加顺序相反。到底是哪个,暂时不清楚。。
支持IE事件处理程序的浏览器有IE和Opera。
5.跨浏览器的事件处理程序
//跨浏览器的事件处理程序 恰当的使用能力检测即可实现 //要保证事件的代码能在大多数浏览器下一致地运行,只需关注冒泡阶段 //第一个要创建的方法是addHandler(),职责是视情况分别使用DOM0级方法、DOM2级方法 //或IE方法来添加事件。这个方法属于一个名叫EventUtil的对象。 //接受三个参数:要操作的元素、事件名称和事件处理程序函数 //removeHandler() 也接受相同的参数。职责是移除之前添加的事件处理程序-无论该事件采取什么方式添加到元素中的,如果其他方法无效,默认采用DOM0级方法 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 handler = function(){ alert("Clicked"); }; //指定 EventUtil.addHandler(btn,"click",handler); //移除事件处理程序 EventUtil.removeHandler(btn,"click",handler); //注意 以上的addHandler()和removeHandler()没有考虑到所有的浏览器问题,例如IE中的作用域问题 //不过,使用它们添加和移除事件处理程序还是足够了。此外还要注意,DOM0级对每个事件支持一个事件处理程序。 //好在,只支持DOM0级的浏览器已经没那么多了。