主要参考 js权威指南和js高级程序设计
JS与HTML的交互是通过
事件来实现的
观察员模式的模型,支持页面行为(javascript)与页面的外观(html css)之间的松耦合
概念:
事件
(event)
:是指用户或者浏览器自身执行的某种动作。如:click、load和mouseover。
事件类型(event type):
用来说明发生什么类型事件的字符串,有时候,称为事件名称(event name),如:'mousemove','keydown','load'
事件目标(event target):
发生的事件与之相关的对象。
事件处理程序(event handle/listener):处理或者响应事件的函数。
事件对象(event object):与特定事件相关且包含有关事件详细信息的对象,事件对象作为参数传递给事件处理程序函数(IE8除外,仅能通过window.event得到)
------------------------------------------------------------------------------------------------------------------------------
--------
事件传播/事件流(event propagation):
描述的是从页面中接收事件的顺序。IE的事件流是事件冒泡流(event bubbling),而其他事件流是事件捕获流(event capturing)。
1、事件冒泡流:事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后,逐级向上传播到较为不具体的节点(文档)。所有现代浏览器都支持事件冒泡,故而,放心使用。
例如:
<!DOCTYPE html>
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>
当你点击<div>元素时,click事件会按照,<div> -> <body> -> <html> -> document的顺序来传播。
2、事件捕获流:是不太具体的节点更早接收到事件,而具体的节点最后接收事件。此种情况下,点击<div>元素时,click事件会按照,document -> <html> -> <body> -> <div>的顺序来传播。
------------------------------------------------------------------------------------------------------------------------------
DOM事件流:
“DOM2级事件”规定的事件流包括三个阶段:
事件捕获阶段、处于目标阶段和事件冒泡阶段。以前面的点击事件为例:
从图中看出,实际目标在捕获阶段不会接收到事件,这意味着在“捕获阶段”,事件从document到<html>再到 <body>后就停止了。下一个阶段是“处于目标”阶段,于是,事件在<div>上发生,并在事件处理中被看成“冒泡阶段”的一部分。然后,冒泡阶段发生,事件又传回document。
--------------------------------------------------------------------------------------------------------------------------
事件处理程序:
响应某个事件的函数叫做事件处理程序,
按照规定,
事件处理程序的属性名称
以“on”开头,后面跟着事件名称,因此click事件的事件处理程序是onclick,load事件的事件处理程序是onload。为事件指定处理程序的方式有好几种。
1、HTML事件处理程序(不推荐
用
):
HTML标签属性作为事件处理程序
属性
,属性值是js代码字符串,即事件处理函数的主体。在执行时,有权访问全局作用域中的任何代码 ,会创建一个封装着元素属性值的函数,这个函数中有一个局部变量event,即事件对象。无需定义它,即可通过event,直接访问事件对象,在这个函数内,this值等于事件的目标元素。
例如:
<input type="button" value="按钮" id="btn" οnclick="alert('hello')">
<script >
function showMessage(){
alert('hello world!!!');
}
</script>
<input type="button" value="按钮" id="btn" οnclick="showMessage()">
缺点:1.
HTML和JS代码紧密耦合在一起,无法给元素添加多个事件。 2. 时差问题,当触发事件时,触发的函数还没有定义,会报js错误,可通过try-catch,来提前捕获js错误。
2、DOM0级事件处理程序:较传统的方式,
每个元素(包括window和document)都有自己的事件处理程序
属性,这些属性需要小写,如onclick,
将这个属性设置为一个函数,就可以指定事件处理程序。
例如:
<input type="button" value="按钮2" id="btn2">
<script >
function showMessage(){
alert('hello world!!!');
}
var btn2 = document.getElementById('btn2');//取得按钮的引用
//给对象以属性方式添加方法
btn2.οnclick=function(){
alert("这是通过DOM0级添加的事件!!!");
}
//删除onclick属性
btn2.οnclick=null;
</script>
优点:简单、跨浏览器
3、DOM2级事件处理程序:(
不兼容IE,需要用IE的事件处理程序)
DOM2级事件定义了两个
方法:
用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener()。
接受三个参数:
要处理的事件名称、作为事件处理程序的函数、布尔值(true,表示在捕获阶段调用事件处理程序,
false,表示在冒泡阶段调用事件处理程序)
例如:
<input type="button" value="按钮3" id="btn3">
<script >
function showMessage(){
alert('hello world!!!');
}
var btn3 = document.getElementById('btn3');//取对象
//事件不加on,兼容浏览器用false
btn3.addEventListener('click', showMessage, false);
//this引用被触发的元素,this相当于but3
btn3.addEventListener('click', function(){
alert(this.value)}, false);
//必须保证removeEventListener与addEventListener中的参数相同
btn3.removeEventListener('click', showMessage, false);
</script>
特点:1. 添加事件处理程序的主要好处是可以添加多个事件处理程序,它们会按照顺序触发。2. removeEventListener()只能移除非匿名函数。
4、IE事件处理程序:
attachEvent()添加事件
detachEvent()删除事件
接受相同的两个参数(IE8之前只支持事件冒泡,默认是事件冒泡,所以不加布尔值):
事件处理程序的属性名称和作为事件处理程序的函数
例如:
<input type="button" value="按钮4" id="btn4">
<script>
function showMessage(){
alert('hello world!!!');
}
//支持IE事件处理程序:IE和opera
var btn4 = document.getElementById('btn4');//取对象
btn4.attachEvent('onclick', showMessage);
// 必须保证attachEvent与detachEvent中的参数相同
btn4.detachEvent('onclick', showMessage);
</script>
特点 :
1. 也可以为一个元素添加多个事件处理程序,但是,与DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是
可能按照任何顺序
被触发(
js高级程序设计P353 13.2 事件处理程序和js权威指南P457 17.3.5 调用顺序观点不一致
)。2. 在使用DOM0级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this等于window。3. detachEvent()只能移除非匿名函数。
5、跨浏览器的事件处理程序
为了以跨浏览器的方式处理事件,我们会使用隔离浏览器差异的js库,自己封装在一个对象内
例如:
<script >
var eventUtil={
//添加句柄,要操作的元素(element),事件名称(type),用什么事件处理程序函数(handler)
addHandler:function(element,type,handler){
if(element.addElementListener){
// DOM2级事件处理程序
element.addEventListener(type,handler,false);
}else if(element.attchEvent){
// IE事件处理程序
element.attachEvent('on'+type,handler);
}else{
// DOM0级事件处理程序,注意js中所有用属性的地方,都可以用[],比如:element.οnclick===element['onclick']
element['on'+type]=handler;
}
}
//删除句柄
removeHandler:function(element,type,handler){
if(element.removeElementListener){
//DOM2级事件处理程序
element.removeEventListener(type,handler,false);
}else if(element.detachEvent){
//IE事件处理程序
element.detachEvent('on'+type,handler);
}else{
//DOM0级事件处理程序
element['on'+type]=null;
}
}
}
var btn = document.getElementById("myBtn");var handler = function(){
alert("Clicked");};
eventUtil.addHandler(btn3, 'click', showMessage);
eventUtil.removeHandler(btn3, 'click', showMessage);
</script >