《JAVASCRIPT高级程序设计》事件处理程序和事件类型

一、事件流

  谈到事件,首要要理解事件流的概念:事件流是指从页面接受事件的顺序;“DOM2级事件”规定事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。目前大部分的浏览器的事件流是事件冒泡,即最开始由具体的元素接收事件,然后逐级传播到不具体的节点,直到传播到windows对象;另一种事件流是事件捕获,目前使用得比较少,是指文档对象先接收到事件,然后逐级向下,一直传播到事件的实际目标。

二、事件处理程序

1、两种表示方式

<input type="button" value = "click me" onclick = "alert(‘Clicked‘)"/>
    <input type="button" value = "click me" onclick = "showMessage()"/>
<script>
    function showMessage(){
        alert("Click");
    }
</script>

2、事件处理程序具有event对象,以及扩展了作用域

    <!-- 函数中有一个event对象表示事件本身,不用自己定义 -->
    <input type="button" value = "click me" onclick = "alert(event.type)"/>
//动态创建的函数具有以下的作用域(默认对原有作用域进行了扩展)
function(){
    with(document){
        with(this.form){
            with(this){
            //元素的属性值
        }
}
}
<form method = "post">
    <input type="text" name = "username" value=""/>
    <!-- 由于扩展了作用域,下列代码的事件可以访问表单的其他元素 -->
    <input type="button" value = "Echo username" onclick = "alert(username.value)"/>
</form>

3、事件处理程序的异常捕获

  以上面的例子来说,假设showMessage()函数是在页面的底部定义的,如果用户在解析showMessage()之前就单击了按钮,就会引发错误,因此,很多HTML事件程序会被封装在一个try-catch语句块中:

<input type="button" value = "Echo username" onclick = "try(showMessage();)catch(ex){}"/>

二、DOM0级以及DOM2级的事件处理程序

1、DOM0级

  从第四代web浏览器开始,就开始采用“通过将函数赋值给事件处理程序属性”的方式来为事件处理程序赋值。每个函数都有自己的事件处理程序属性,以下是将属性设置成一个函数的例子:

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert(this.id);
}

  删除DOM0级的事件处理程序,需要把事件处理程序属性置空。

btn.onclick = null;

2、DOM2级

  DOM2级事件定义了两个方法,用于处理和删除事件处理程序的操作,addEventListener()和removeEventListener()。所有的DOM节点都包含这两个操作,并且它们都接受3个方法:要处理的事件名、作为事件处理程序的函数以及一个布尔值;布尔值的true和false分别表示在捕获阶段和在冒泡阶段调用事件处理程序。通过这种方式添加的事件处理程序会按照添加它们的方式触发。

var btn = document.getElementById("myBtn");
var handler = function(){
    alert(this.id);
}
//添加事件处理程序
btn.addEventListener("click",handler,false);
//移除事件处理程序
btn.removeEventListener("click",handler,false);

3、IE事件处理程序

  IE事件处理程序实现了与DOM相似的两个方法:attachEvent()和detachEvent(),它们的区别是:后者只支持冒泡事件;事件处理程序是在全局作用域运行而不是所属元素的作用域;添加多个事件时不是顺序执行,而是以相反的顺序触发。

var btn = document.getElementById("myBtn");
var handler = function(){
    alert(this.id);
}
//添加事件处理程序
btn.attachEvent("onclick",handler);
//移除事件处理程序
btn.detachEvent("onclick",handler);

4、跨浏览器的事件处理程序

  要保证事件在大多数情况运行,只需要关注冒泡阶段,并视情况使用DOM0、DOM2级或IE方法来添加事件。

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.attachEvent){
            element.detachEvent("on"+type, handler);
        }else{
            element["on"+type] = null;
        }
    }
};

  之后可以像下面这样来使用EventUtil对象:

var btn = document.getElementById("myBtn");
var handler = function(){
    alert("clicked");
}
EventUtil.addHandler(btn, "click", handler );
EventUtil.removeHandler(btn, "click", handler);

三、事件对象

1、DOM中的事件对象

  在触发DOM的某个事件时,会产生一个事件对象event,这个对象包含着所有与事件有关的信息。触发事件的类型不一样,可用的属性和方法也不一样。不过,所有的事件都会有以下成员:

  以下是一些常见的使用以上方法和属性的例子:

// 需要通过一个函数处理多个事件时,可以利用type属性
var btn = document.getElementById("myBtn");
var handler = 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;
    }
};
// 使用DOM0级事件
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
// 阻止事件的默认行为
var link = document.getElementById("myLink");
link.onclick = function(event){
    event.preventDefault();
}
// 阻止事件在DOM层次的传播,以下只会出现一个弹窗
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
    alert("Clicked");
    event.stopPropagation();
}
document.body.onclick = function(event){
    alert("Body Clicked");
}

2、IE中的事件对象以及跨浏览器的解决方案

  IE中的event对象包含的属性与DOM中的不同,具体为:

  IE中event对象的全部信息和方法,DOM对象中都有,只是实现方式不同;通过对应关系,可以实现两种事件模型之间的映射。以下通过对EventUtil对象加以增强来映射:

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.attachEvent){
            element.detachEvent("on"+type, handler);
        }else{
            element["on"+type] = null;
        }
    },
    getEvent:function(event){
        // 在ie中,当通过DOM0级方法添加事件处理程序时,event是作为window的一个属性存在的
        // 在ie中,当通过DOM2级方法添加事件处理程序时,event可以直接返回
        // 在DOM对象中,event可以直接返回
        return event ? event : window.event;
    },
    getTarget:function(event){
        return event.target || event.srcElement;
    },
    preventDefault: function(event){
        if(event.preventDefault){
            event.preventDefault();
        }else{
            event.returnValue = false;
        }

    },
    stopPropagation: function(event){
        if(event.stopPropagation()){
            event.stopPropagation();
    }else{
        // IE不支持事件捕获,只能取消冒泡事件
        event.cancelBubble = true;
    }
};

四、事件类型

  web浏览器中可能发生的事件类型有很多,不同的事件类型具有不同的事件信息;HTML5也定义了一组事件;DOM2级也有事件模块;DOM3级事件模块在DOM2级事件模块的基础上重新定义了事件,也添加了一些新事件;有些浏览器还实现了一些专有事件。以下分别介绍。

1、DOM3级事件

1)UI事件

// load事件,页面完全加载完后,会触发window上的load事件
// 用javascript触发load事件
EventUtil.addHandler(window, "load", function(event){
    alert("Loaded");
});
<!--load事件,在html上触发,这是向后兼容的一种权宜之计-->
<body onload = "Loaded">
</body>
// 有时候在DOM中添加新元素时,需要确定页面已经加载完毕,可以使用load事件
// 添加新图像
EventUtil.addHandler(window, "load", function(){
    var image = document.createElement("img");
    EventUtil.addHandler(image, "load", function(event){
        event = EventUtil.getEvent(event);
        alert(EventUtil.getTarget(event).src);
    });
    document.body.appendChild(image);
    image.src = "smile.gif";
    // 新图像元素不一定要从添加到文档后才开始下载,只要指定了src属性,就会开始下载
});

// 添加新脚本
EventUtil.addHandler(window, "load", function(){
    var script = document.createElement("script");
    EventUtil.addHandler(script, "load", function(event){
        alert("loaded");
    });
    document.body.appendChild(script);
    script.src = "example.js";
    // 新脚本只有在设置了src属性并将其添加到文档后,才会开始下载
});

// 添加新css文件
EventUtil.addHandler(window, "load", function(){
    var link = document.createElement("link");
    link.type = "text/css";
    link.rel = "stylesheet";
    EventUtil.addHandler(link, "load", function(event){
        alert("css coaded");
    });
    document.body.appendChild(link);
    link.href = "example.css";
    // 新css文件只有在设置了href属性并将其添加到文档后,才会开始下载
});

2)unload事件

  在文档被完全卸载后触发,利用这个事件最多的情况是清除引用,以避免内存泄露。

// 用javascript触发unload事件
EventUtil.addHandler(window, "unload", function(event){
    alert("unLoaded");
});
<!--unload事件,在html上触发-->
<body onload = "unLoaded">
</body>

3)resize事件

  当浏览器调整到新高度或宽度时触发:

EventUtil.addHandler(window, "resize", function(event){
    alert("resized");
});

4)scroll事件

  页面滚动位置变化时触发,可以通过<body>元素的scrollLeft和scrollTop来监控变化:

EventUtil.addHandler(window, "scroll", function(event){
    if(document.compatMode == "CSS1Compat"){
        alert(document.documentElement.scrollTop);
    }else{
        alert(body.scrollTop);
    }
});

5)焦点事件

  焦点事件一共有6个,当焦点从页面的一个元素移动到另外一个元素时,会依次触发:

  • focusout:在失去焦点的元素上触发
  • focusin:在获得焦点的元素上触发
  • blur:在失去焦点的上元素触发
  • DOMFucusOut:在失去焦点的元素上触发
  • focus:在获得焦点的元素上触发
  • DOMFucusIn:在获得焦点的元素上触发

6)鼠标与滚轮事件

  一次双击事件中,相关的事件会按照以下的顺序触发:

  • mousedown
  • mouseup
  • click
  • mousedown
  • mouseup
  • click
  • dbclick

  以下是获取鼠标坐标位置的一些例子:

// example1: 常用位置获取方式
    var div = document.getElementById("myDiv");
    EventUtil.addHandler(div, "click", function(event){
        event = EventUtil.getEvent(event);
        // 获取鼠标在浏览器视口的位置
        alert("Client coordinates:"+event.clientX + "," +event.clientY);

        // 获取鼠标在页面的坐标位置
        alert("Client coordinates:"+event.pageX + "," +event.pageY);

        // 获取鼠标在电脑屏幕中的位置
        alert("Client coordinates:"+event.screenX + "," +event.screenY);
    });
// example2:存在页面滚动时,获取鼠标在页面的坐标位置
    var div = document.getElementById("myDiv");
    EventUtil.addHandler(div, "click", function(event){
        event = EventUtil.getEvent(event);
        var pageX = event.pageX,
            pageY = event.pageY;

        if(pageX == undefined){
            // 需要用到混杂模式document.body或者标准模式document.documentElement中的scrollLeft和scrollTop属性
            pageX = event.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft);
        }
        if(pageY == undefined){
            pageY = event.clientX + (document.body.scrollTop || document.documentElement.scrollTop);
        }
        alert("Client coordinates:"+pageX + "," +pageY);
    });

  虽然鼠标事件主要是使用鼠标来触发的,但是在按下鼠标时,键盘上某些键的状态也可能影响到要采取的操作,这些键是:Shift, Ctrl, Alt, Meta(windows 上是windows键, apple上是cmd键);Dom定义了一些属性来表示这些键的状态,如下例:

// example3:
    var div = document.getElementById("myDiv");
    EventUtil.addHandler(div, "click", function(event){
        event = EventUtil.getEvent(event);
        var keys = new Arrary();

        if(event.shiftKey){
            keys.push("shift");
        }
        if(event.ctrlKey){
            keys.push("ctrl");
        }
        if(event.altKey){
            keys.push("alt");
        }
        if(event.metaKey){
            keys.push("meta");
        }

        alert("keys:" + keys.join(","));
    });

  鼠标滚轮事件:当用户通过鼠标与页面交互、在垂直方向上滚动页面时,就会触发鼠标滚轮事件mousewheel(IE, Chrome, Opera, safari)或者DOMMouseScroll(firefox),这个事件可以在任意元素触发,最终冒泡到document或者window。

  另外,触摸设备是没有鼠标的,这些设备相关的事件,具有以下特点:

  • 不支持dbclick事件
  • 轻击可单击元素会触发mousemove事件
  • mousemove事件也会触发mouseover和mouseout事件
  • 两个手指放在触摸屏上且页面随手指滚动时会触发mousewheel和scroll事件

7)键盘与文本事件

  对键盘事件的支持主要是DOM0级,DOM2级没有对此作出规定,DOM3级对此实现了规范。键盘事件有3个,文本事件有1个:

  • keydown:用户按下任意键时触发
  • keypress:用户按下键盘上的字符键触发
  • keyup:用户释放键盘的键时触发
  • textInput:在文本插入文本框之前触发,用意是在将文本显示给用户之前拦截文本进行处理

  在发生keydown和keypress事件时,event对象的keycode或者charcode属性会包含一个代码,与键盘上一个特定的键对应。由于不同浏览器对该属性的支持不同,要以跨浏览器的方式取得字符编码,必须首先检测charcode属性是否可用;如不可用,再使用keycode, 如下例:

    function getCharCode(event){
        if(typeof event.charCode == "number"){
            return event.charCode;
        }else{
            return event.keyCode;
        }
    }

  DOM3级事件新增了key, keyIdentifier和char属性来实现键盘事件,但是由于存在跨浏览器的问题,因此不推荐使用。另外,DOM3级事件还添加了一个名为location的属性,表示按下了什么位置的键,1表示左侧位置(例如左侧位置的alt键),2表示右侧位置(例如右侧位置的shift键)。支持location属性的浏览器也不多,因此也不推荐使用。

8)复合事件

  复合事件是DOM3新添加的一类事件,用于处理IME的输入序列。IME(input method editor, 输入法编辑器),可以让用户在物理键盘输入找不到的字符。有以下三种复合事件:

  • compositionstart: 在IME的文本复合系统打开时触发,表示要开始输入了。
  • compositionupdate: 在向输入字段中插入新字符时触发。
  • compositionend: 在IME的文本复合系统关闭时触发,表示返回正常键盘输入状态。

  对于跨浏览器的开发,复合事件的用处也不大。

9)变动事件

  DOM2级的变动事件能在DOM的某一部分发生变化时给出提示;定义了如下变动事件:

  • DOMSubtreeModified:在DOM结构发生任何变化时触发
  • DOMNodeInserted:在一个节点作为子节点被插入到另一个节点时触发
  • DOMNodeRemoved:在节点从其父节点中被移除时触发
  • DOMInsertedIntoDocument:在一个节点被直接插入文档或通过子树间接插入文档后触发
  • DOMNodeRemovedFromDocument:在一个节点直接从文档中移除或间接从文档中移除后触发
  • DOMAttrModified:在特性被修改之后触发
  • DOMCharacterDataModified:在文本节点的值发生变化时触发

2、HTML5事件

  DOM规范没有涵盖所有浏览器支持的事件,很多浏览器出于不同的目的,实现了一些自定义事件。HTML5详尽的列出了浏览器应该支持的事件,下面简单介绍:

1)contextmenu事件

  Windows95在PC上引入了上下文菜单的概念,即通过鼠标右键单击可以调出上下文菜单。开发人员面临的问题是,如何确定应该显示上下文菜单,以及如何屏蔽与该操作关联的默认上下文菜单。contextmenu事件是为了解决这个问题而提出的。

2)beforeunload事件

  这个事件会在浏览器卸载页面之前触发,这个事件的意图是将页面的控制权交给用户。例如,通过弹窗告知用户页面将进行卸载,询问用户是否真的要关闭页面,还是希望继续留下来。

3)DOMContentLoaded事件

  window的load事件会在页面中的一切都加载完毕后触发,但这个过程可能会因为要加载的外部资源过多而颇费周折。而DOMContentLoaded事件则在形成完整的DOM树后就会触发,丝毫不理会图像、JAVASCRIPT文件、CSS文件或者其他资源是否下载完毕。

4)readystatechange事件

  这个事件的目的是提供与文档或元素的加载状态有关的信息,支持该事件的每个对象都有一个readyState属性,可能包含下列5各值中的一个:

  • uninitialized: 对象存在但尚未初始化
  • loading:对象正在加载数据
  • loaded:对象加载数据完成
  • interactive:可以操作对象了,但还没有完全加载
  • complete:对象已经加载完毕

3、设备事件

  智能手机与平板电脑的普及,为用户与浏览器的交流引入了一种新的方式,一种新一类的事件——设备事件也应运而生。下面简要介绍几种设备事件:

1)orientationchange事件

  苹果公司为移动safari中添加了orientationchange事件,以便开发人员能够确定用户何时将设备由横向查看模式切换为纵向查看模式。

2)MozOrientation事件

  Firefox为检测设备的方向引入了MozOrientation事件。当设备的加速计检测到设备方向改变时,就会触发这个事件。

3)deviceorientation事件

  该事件与MozOrientation事件相似,也是加速计检测到设备方向变化时,在window对象上触发,不过deviceorientation事件的意图是告诉开发人员,设置在空间中朝向哪儿,而不是如何移动。

4)devicemotion事件

  该事件是要告诉开发人员设备什么时候移动,而不仅仅是设备方向如何移动。例如,通过devicemotion事件可以检测到设备是不是正在往下掉,或者是不是被走着的人拿在手里。

4、触摸与手势事件

   随着触摸设备的增加,一些少数设备的专有事件也开始变成了事实标准。Touch Events定义了如下触摸事件和手势事件:

1)触摸事件

  • touchstart:手指触摸屏幕时触发
  • touchmove:手指在屏幕上滑动时连续触发
  • touchend:手指在屏幕上移开时触发
  • touchcancel:当系统停止跟踪触摸时触发

2)手势事件

  • gesturestart:当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发
  • gesturechage:当触摸屏幕的任何一个手指的位置发生变化时触发
  • gestureend:当任何一个手指从屏幕上移开时触发
时间: 2024-10-16 19:26:01

《JAVASCRIPT高级程序设计》事件处理程序和事件类型的相关文章

javascript高级程序设计 第十三章--事件

javascript高级程序设计 第十三章--事件js与HTML的交互就是通过事件实现的,事件就是文档或浏览器窗口中发生的一些特定的交互瞬间. 事件流:事件流描述的是从页面中接收事件的顺序,IE的是事件冒泡流,Netscape的是事件捕获流,这个两个是完全相反的事件流概念. 事件冒泡:由最具体的元素接收,然后逐级向上传播到更高级的节点,即事件沿DOM树向上传播,直到document对象. 事件捕获:不大具体的节点应该更早接收到事件,相当于沿DOM节点树向下级传播直到事件的实际目标,在浏览器中,是

《JavaScript高级程序设计》Chapter 13 事件

小记 JS与HTML之间的交互通过事件实现,事件发生在交互的瞬间,可以使用事件监听器(或者事件处理程序)来预定时间.DOM2事件模块尽量对事件进行规范,然而DOM3又增加了一些额外的处理方式,再加上BOM和浏览器之间的差异性,事件处理有的时候会十分的复杂.但仍然需要了解基本的概念. 导航 事件流的概念 go 事件处理程序(HTML.DOM0.DOM2以及IE的大体运作方式,跨浏览器处理) go 事件对象(event.DOM和IE的差别,跨浏览器处理)go 事件类型(列举各种常用事件类型,了解一些

JavaScript 高级程序设计 学习笔记 1 基础类型。

/************************************************************************************************************* * @第二章 在HTML 中使用Javascript */<script> 标签属性 async 可选:表示立即下载脚本,但不妨碍页面中的其他操作,只对外部文件有效. defer 可选:表示脚本可以延迟都文档完全被解析和显示之后再执行,只对外部文件有效. src 可选:表示包

web前端之JavaScript高级程序设计六:事件

web前端之JavaScript高级程序设计六:事件 JavaScript 与 HTML 之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间.可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码.这种在传统软件工程中被称为观察员模式的模型,支持页面的行为(JavaScript 代码)与页面的外观(HTML 和 CSS 代码)之间的松散耦合. 事件流: 事件流描述的是从页面中接收事件的顺序.但有意思的是, IE 和 Netscape 开发团队居然提出了

《javascript高级程序设计》 touch事件的一个小错误

最近一段时候都在拜读尼古拉斯大神的<javascript高级程序设计>,真的是一本好书,通俗易懂,条理比<javascript权威指南>好理解一些,当然<javascript权威指南>有权威指南的优点,不闲话了,入正题. 看技术书我通常都喜欢把书上的代码敲一遍,虽然很花时间,但只有动手敲的时候,脑中才有各种乱七八糟的想法蹦出来,为什么不能按照自己想的写,为什么书上的代码更好更优雅,还有没有别的办法去解决眼前的问题,想的多了,理解就很深,当然最重要的就是记得牢了.即使很浅

JavaScript高级程序设计之Date类型

ECMAScript 中的 Date 类型是在早期 Java 的 java.util.Date 类基础上构建的. Date 类型使用自 UTC (国际协调时间)1970年1月1日午夜(零时)开始经过的毫秒数来保存日期. Date 对象的valueOf()方法可以获取这个毫秒数. 使用本地化UTC的方式是较好的方式. var now = new Date(), // 这是最推荐的方式,本地时间为1986年5月24日 12:30:30 birthday = new Date(1986, 4, 24,

JavaScript高级程序设计(第三版)学习笔记20、21、23章

第20章,JSON JSON(JavaScript Object Notation,JavaScript对象表示法),是JavaScript的一个严格的子集. JSON可表示一下三种类型值: 简单值:字符串,数值,布尔值,null,不支持js特殊值:undefined 对象:一组无序的键值对 数组:一组有序的值的列表 不支持变量,函数或对象实例 注:JSON的字符串必须使用双引号,这是与JavaScript字符串最大的区别 对象 { "name":"Nicholas"

JavaScript高级程序设计51.pdf

(续上篇) 模拟鼠标事件 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); /

JavaScript高级程序设计24.pdf

Element类型 Element类型用于表现XML或HTML元素,提供对元素标签名.子节点及特性的访问,它具有以下特征 nodeType的值为1: nodeName的值为元素的标签名: nodeValue的值为null: parentNode可能是Document或Element: 要访问元素的标签名可以使用nodeName属性或者tagName属性,两者返回相同的值 <div id="myDiv"></div> var div=document.getEle

JavaScript高级程序设计60.pdf

错误处理 try-catch语句 try{ //可能会导致错误的代码 }catch(error){ //在错误发生时如何处理 } error是一个包含着错误信息的对象,它有一个message属性,保存着错误消息:还有一个保存着错误类型的name属性(Opera9之前不支持这个属性) try{ //可能会导致错误的代码 }catch(error){ alert(error.message); } finally子句 try{ //可能会导致错误的代码 }catch(error){ //在错误发生时