什么是HTML DOM事件(Events)?
- 事件是可以被JavaScript检测到的行为
- 网页中的每个元素都可以产生某些可以触发JavaScript函数或程序的事件;比如:当用户单机按钮或者提交表单数据时,就发生一个鼠标(onclick)事件,需要浏览器做出处理,返回给用户一个结果;
- HTML事件可以是浏览器行为,也可以是用户行为;
- 事件的分类:
- 窗体事件
- 鼠标事件
- 键盘事件
- 表单事件
事件流:
描述的是从页面中接收事件的顺序;IE事件流是事件冒泡流,而Netscape(网景)的事件流是事件捕获流;这两种事件流的概念几乎完全相反
- 事件冒泡:IE事件流叫做事件冒泡,即事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播至最不具体的那个节点(文档);也就是说一个标签元素处理完事件之后,它的父元素、父元素的父元素也都会处理事件(从内到外)
- 事件捕获:Netscape(网景)的事件流叫做事件捕获,不太具体的节点(最外层标签)应该更早接收到事件,而最具体的节点(最内层标签)最后接收到事件(事件执行的顺序是从外到内);由于老版本浏览器不支持,因此很少有人使用事件捕获。建议大家放心地使用事件冒泡,在有特殊需要时再使用事件捕获。
事件处理程序:
事件就是用户或者浏览器自身执行的某种动作。如:click、load和mouseover等,都是事件的名字。而响应某个事件的函数就叫做事件处理程序(或事件侦听器;
事件处理程序的名字以"on"开头,因此对应事件处理程序就是onclick、onload。为事件指定处理程序的方式有如下几种:
- HTML事件处理程序:说白了就是html中的事件属性,如:onclick onmouseover等,使得html元素具有能够执行js代码的特性:
<button onclick="alert('html事件处理程序')">点击我</button>
<marguee onmouseover="this.start()" onmouseout="this.stop()"></marquee>
这里,关于this关键字的使用:
- 在标签中使用,代表的是标签本身
- 在函数体中直接使用,代表的是window;在标签中将this作为实参传递到函数中,在函数体中使用形参代表标签本身
- 在事件函数中使用,代表标签本身。这种事件处理程序有两个缺点:
- 存在一个时差的问题,如果将script程序写在页面的最底部,而用户又在html元素一出现就触发相应的事件,这个时候事件处理程序有可能尚不具备执行条件(即:script程序未加载,dom从上往下依次解析html文件)
- html代码与Js代码紧密耦合,这样在维护或修改时需要修改两个地方。所以建议摒弃html事件处理程序,进而使用js指定事件处理程序
- DOM0级事件处理程序:通过Js指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。这种操作简单且具有跨浏览器的优势
var btn = document.getElementById('btn');
btn.onclick = function(){
alert("DOM0级事件处理程序");
}
提示:
- 使用DOM0级方法指定的事件处理程序被认为是元素的方法;因此这时候的事件处理程序是在元素的作用域中运行;即:程序中的this引用的是当前元素
var btn = document.getElementById('btn');
btn.onclick = function(){
alert(this.id);//btn
}
- 这种方式添加的事件处理程序会在事件流的冒泡阶段被处理;
- 移除(删除)DOM0级方法指定的事件处理程序的方法,删除后点击按钮不会有任何效果 btn.onclick = null; //删除事件处理程序,将点击事件设置为null
- DOM2级事件处理程序:
DOM2级事件定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener();他们都接收三个参数,要处理的事件名、作为事件处理程序的函数和一个布尔值:
var btn = document.getElementById('btn');
//添加DOM2事件处理程序
btn.addEventListener('click',handler,false);
//此处事件不在加前缀"on",add为自定义函数如下需要创建声明,第三个布尔值参数为false为默认值,代表事件句柄在冒泡阶段执行,若为true代表 事件句柄在捕获阶段执行
var handler = function(){
//函数体
}
//移除DOM2事件处理程序
btn.removeEventListener('click',handler,false);
提示:
- 与DOM0事件一样,DOM2事件处理程序也是在其依附元素的作用区域中运行;不同之处在于,DOM2级事件处理程序可以添加多个事件处理程序,那么在触发时会按照顺序依次触发,如下依次显示"哈哈"、"呵呵"
var btn = document.getElementById('btn');
btn.addEventListener('click',function(){//这里使用的是匿名函数
alert("哈哈");
});
btn.addEventListener('click',function(){//这里使用的是匿名函数
alert("呵呵");
});
- 通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除,移除时传入的参数与添加处理程序时使用的参数相同;那么这也就意味着通过addEventListener()添加的匿名函数是无法移除的
- IE事件处理程序:IE实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。由于IE8及更早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段:
- attachEvent("事件处理程序名称",事件处理程序函数) 添加事件
- detachEvent("事件处理程序名称",事件处理程序函数) 删除事件
var btn = document.getElementById('btn');
btn.attachEvent("onclick",function(){//注意:这里事件处理程序的名称是"onclick",不是DOM2级事件中的'click'
alert("呵呵!!");
});
提示:
- 与DOM0级方法的区别在于事件处理程序的作用域不同:DOM0级是在其所属元素的作用域内运行,而IE事件处理程序是在全局作用域运行,因此this等于window:
var btn = document.getElementById('btn');
btn.attachEvent("onclick",function(){
alert(this === window); //true
});
- 与DOM2级方法一样,可以为同一个按钮添加两个不同事件处理程序,但是IE事件处理程序的执行顺序是以相反的顺序触发,即先触发的是后面添加的事件
- 使用detachEvent()来移除通过attachEvent()方法添加的事件,与DOM2级方法一样,匿名函数无法被移除
- 跨浏览器的事件处理程序(即:事件的兼容性处理)
- 使用隔离浏览器差异的javascript (helper) 库(JavaScript库常被称为JavaScript框架,如jQuery、MooTools、Prototype) www.w3school.com.cn/js/js_libra…
- 自己开发最合适的事件处理方法,使得代码在冒泡阶段处理事件时能最大限度地兼容大多数浏览器。这里介绍一个名叫EventUtil的对象,它可以用来处理浏览器的差异,这里面用到它的一个addHandler()方法,此方法接受3个参数, 分别是:要操作的元素、事件的名称和事件处理程序函数。www.cnblogs.com/hykun/p/Eve… 使用addHandler()方法添加的事件程序可以使用removeHandler()方法移除,接受的参数与addHandler()方法相同 EventUtil对象内部结构如下:
var EventUtil = {//对象
addHandler: funtion(element,type,handler){
if(element.addEventListener){//DOM2事件处理程序
element.addEventListener(type,handler,false);//默认是false,在冒泡阶段执行,可以省略
}else if(element.attachEvent){//IE事件处理程序
element.attachEvent('on'+type,handler);//这里为了兼容IE8及以前版本,必须加上on
}else{
element['on'+type] = handler;//其它方法无效,则采用DOM0级方法,这里使用方括号语法将属性名指定为事件处理程序,同"."(obj.att)
}
}
removeHandler: function(elment,type,handler){
if(element.removeEventListener){
element.removeEventListener(type,handler,false);
}else if(element.detachEvent){
element.detachEvent("on" + type, handler);
}else{
element["on" + type] = null; //其它方法无效,DOM0级方法删除事件处理程序
}
}
}
关于EventUtil对象的使用如下:
var btn = document.getElementById('btn');
var handler = function(){//事件处理程序的函数
alert('关于EventUtil对象的使用');
}
EventUtil.addHandler(btn,'click',handler);//添加事件处理程序
//过程其它代码...
EventUtil.removeHandler(btn,'click',handler);//移除事件处理程序
面试题:简述DOM0、DOM2、IE事件处理程序有什么不同?
事件对象 event
- event事件对象,表示用来获取事件的详细信息,比如得到鼠标的横坐标:事件对象.clientX(clientX是可视区坐标)
window.onclick = function(ev){
var oEvent = ev || event;//event为IE8和IE8以下浏览器浏览器事件对象可以直接使用;
//以上代码可以判断是否传递了事件对象参数,如果传递了则使用传递的事件对象ev,否则使用window.event
alert(oEvent.type);//click类型
}
- 事件对象的兼容写法
- IE8和IE8以下浏览器不能传递参数,只能使用window.event对象。
- 谷歌浏览器既可以传递事件对象参数,也可以使用window.envent对象,十分全面。
- 火狐浏览器只能使用传递的事件对象参数。因此针对不同浏览器,兼容性写法如下:
事件.事件类型 = function(ev){//事件类型如鼠标点击事件
var oEvent = ev || event;
}
- DOM中的事件对象
- type -- 获取事件类型
- target -- 事件目标
- stopPropagation() -- 阻止事件冒泡(支持DOM事件程序的浏览器)
- preventDefault() -- 阻止事件的默认行为
- IE中的事件对象
- type -- 获取事件类型
- srcElement -- 事件目标 以下两种都可以阻止事件冒泡:
- cancelBubble = true; -- 阻止事件冒泡(IE8及以前浏览器版本)
- returnValue = false; -- 阻止事件的默认行为
- 阻止事件冒泡的兼容性写法
事件.事件类型 = function(ev){ ...}如下:阻止btn元素的事件冒泡
var btn = document.elementById('btn');
btn.onclick = function(ev){
oEvent = ev || event;
//阻止事件冒泡
oEvent.cancelBubble = true;//IE8及以前浏览器版本
oEvent.stopPropagation();//支持DOM2事件处理程序的浏览器
}
- 实例:使用事件绑定的方式实现拖拽
- 获取事件目标的兼容性写法
var btn = document.elementById('btn');
btn.onclick = function(ev){
oEvent = ev || event;
var target = oEvent.srcElement||oEvent.target;
//注意:DOM及IE中默认阻止事件的行为oEvent.preventDefault();与oEvent.returnValue=false;不能阻止事件冒泡
}
- 阻止事件传递的兼容性写法
function cancleHandler(ev){
var oEvent = ev || event;
//事件处理的代码...
//取消事件相关的默认行为
if(oEvent.preventDefault){
oEvent.preventDefault(); // 标准技术(DOM事件对象)
}
if(oEvent.returnValue){
oEvent.returnValue = false; //IE事件对象
}
return false;//用于处理使用对象属性注册的处理程序
}
return false
ev.preventDefault()
提示:取消事件的相关默认操作只是事件取消中的一种,我们还可以通过阻止事件冒泡来取消事件的传播
阻止事件冒泡的兼容性写法
stopPropagation()方法可以在事件传播期间的任何时间调用,它能在捕获阶段、事件目标本身和冒阶段工作,调用这个方法后,任何其它对象上的事件处理程序将不会被调用;
IE8及以前浏览器不支持stopPropagation()方法,而IE事件对象却有一个cancelBubble属性,设置这个属性为true就能阻止事件的进一步传播(IE8及之前浏览器版本不持支事件传播的捕获阶段,所以只取消冒泡阶段的事件传播)