首页 > 代码库 > web前端之JavaScript高级程序设计六:事件

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

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

JavaScript 与 HTML 之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码。这种在传统软件工程中被称为观察员模式的模型,支持页面的行为(JavaScript 代码)与页面的外观(HTML 和 CSS 代码)之间的松散耦合。

事件流:

事件流描述的是从页面中接收事件的顺序。但有意思的是, IE 和 Netscape 开发团队居然提出了差不多是完全相反的事件流的概念。 IE 的事件流是事件冒泡流,而 Netscape Communicator 的事件流是事件捕获流。

事件冒泡:

IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。
也就是说, click 事件首先在div元素上发生,而这个元素就是我们单击的元素。然后,click事件沿 DOM 树向上传播,在每一级节点上都会发生,直至传播到 document 对象。
技术分享

事件捕获:

事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前捕获它。

技术分享

由于老版本的浏览器不支持,因此很少有人使用事件捕获。我们也建议读者放心地使用事件冒泡,在有特殊需要时再使用事件捕获。

DOM事件流:

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。
技术分享

事件处理程序:

事件就是用户或浏览器自身执行的某种动作。诸如 click、 load 和 mouseover,都是事件的名字。而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以”on”开头,因此click 事件的事件处理程序就是 onclick, load 事件的事件处理程序就是 onl oad。为事件指定处理程序的方式有好几种。

HTML事件处理程序:

某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性来指定。这个特性的值应该是能够执行的 JavaScript 代码。例如,要在按钮被单击时执行一些 JavaScript:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>事件</title>
<script type="text/javascript">
function showMessage(){
    alert("Hello World!");
}
</script>
</head>
<body>
    <input type="button" value="Click me" onclick="showMessage()">
</body>
</html>

在这个例子中,单击按钮就会调用 showMessage()函数。这个函数是在一个独立的script元素中定义的,当然也可以被包含在一个外部文件中。事件处理程序中的代码在执行时,有权访问全局作用域中的任何代码。

这样指定事件处理程序具有一些独到之处。首先,这样会创建一个封装着元素属性值的函数。这个函数中有一个局部变量 event,也就是事件对象(后续的学习中会有涉及):

<input type="button" value="Click Me" onclick="alert(event.type)">

通过 event 变量,可以直接访问事件对象,你不用自己定义它,也不用从函数的参数列表中读取。
在这个函数内部, this 值等于事件的目标元素,例如:

<input type="button" value="Click Me" onclick="alert(this.value)">

DOM0 级事件处理程序:

通过 JavaScript 指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。这种为事件处理程序赋值的方法是在第四代 Web 浏览器中出现的,而且至今仍然为所有现代浏览器所支持。原因一是简单,二是具有跨浏览器的优势。要使用 JavaScript 指定事件处理程序,首先必须取得一个要操作的对象的引用。

每个元素(包括 window 和 document)都有自己的事件处理程序属性,这些属性通常全部小写,例如 onclick。将这种属性的值设置为一个函数,就可以指定事件处理程序,如下所示:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>事件</title>
<script type="text/javascript">
window.onload=function(){
    var btn=document.getElementById("myBtn");
    btn.onclick=function(){
        alert("Clicked");
    };
};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

btn.onclick = null; //删除事件处理程序
将事件处理程序设置为 null 之后,再单击按钮将不会有任何动作发生。

DOM2 级事件处理程序:

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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>事件</title>
<script type="text/javascript">
window.onload=function(){
    var btn=document.getElementById("myBtn");
    btn.addEventListener("click",function(){
        alert(this.id);
    },false);
};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

使用 DOM2 级方法添加事件处理程序的主要好处是可以添加多个事件处理程序。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>事件</title>
<script type="text/javascript">
window.onload=function(){
    var btn=document.getElementById("myBtn");
    btn.addEventListener("click",function(){
        alert(this.id);
    },false);
    btn.addEventListener("click",function(){
        alert("Hello Word");
    },false);
};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

这里为按钮添加了两个事件处理程序。这两个事件处理程序会按照添加它们的顺序触发,因此首先会显示元素的ID,其次会显示”Hello world!”消息。

通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()来移除;移除时传入的参数与添加处理程序时使用的参数相同。这也意味着通过 addEventListener()添加的匿名函数将无法移除,如下面的例子所示:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>事件</title>
<script type="text/javascript">
window.onload=function(){
    var btn=document.getElementById("myBtn");
    btn.addEventListener("click",function(){
        alert(this.id);
    },false);
    btn.addEventListener("click",function(){
        alert("Hello Word");
    },false);
    btn.removeEventListener("click",function(){//无效
        alert(this.id);
    },false);
};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

在这个例子中,我们使用addEventListener()添加了一个事件处理程序。虽然调用 removeEventListener()时看似使用了相同的参数,但实际上,第二个参数与传入 addEventListener()中的那一个是完全不同的函数。而传入removeEventListener()中的事件处理程序函数必须与传入addEventListener()中的相同,如下面的例子所示。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>事件</title>
<script type="text/javascript">
window.onload=function(){
    var btn=document.getElementById("myBtn");
    var handler=function(){
        alert(this.id);
    };
    btn.addEventListener("click",handler,false);
    btn.addEventListener("click",function(){
        alert("Hello Word");
    },false);
    btn.removeEventListener("click",handler,false);
};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

重写后的这个例子没有问题,是因为在 addEventListener()和 removeEventListener()中使用了相同的函数。大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。最好只在需要在事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段。如果不是特别需要,我们不建议在事件捕获阶段注册事件处理程序。

IE事件处理程序:

IE 实现了与 DOM 中类似的两个方法: attachEvent()和 detachEvent()。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。由于 IE8 及更早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>事件</title>
<script type="text/javascript">
window.onload=function(){
    var btn=document.getElementById("myBtn");
    btn.attachEvent("onclick",function(){
        alert("Clicked");
    });
};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

1.注意,attachEvent()的第一个参数是”onclick”,而非 DOM 的 addEventListener()方法中的”click”。
2.在 IE 中使用 attachEvent()与使用 DOM0 级方法的主要区别在于事件处理程序的作用域。在使用 DOM0 级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用 attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window。
3.与addEventListener()类似, attachEvent()方法也可以用来为一个元素添加多个事件处理程序。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>事件</title>
<script type="text/javascript">
window.onload=function(){
    var btn=document.getElementById("myBtn");
    btn.attachEvent("onclick",function(){
        alert("Clicked");
    });
    btn.attachEvent("onclick",function(){
        alert("Hello World!");
    });
};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

这里调用了两次 attachEvent(),为同一个按钮添加了两个不同的事件处理程序。不过,与 DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。单击这个例子中的按钮,首先看到的是”Hello world!”,然后才是”Clicked”。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>事件</title>
<script type="text/javascript">
window.onload=function(){
    var btn=document.getElementById("myBtn");
    var handler=function(){
        alert("Clicked");
    };
    btn.attachEvent("onclick",handler);
    btn.detachEvent("onclick",handler);
};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

使用 attachEvent()添加的事件可以通过 detachEvent()来移除,条件是必须提供相同的参数。与 DOM 方法一样,这也意味着添加的匿名函数将不能被移除。不过,只要能够将对相同函数的引用传给 detachEvent(),就可以移除相应的事件处理程序。

跨浏览器的事件处理程序:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>跨浏览器兼容</title>
<script type="text/javascript">
window.onload=function(){
    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;
            }
        }
    };
};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

这两个方法首先都会检测传入的元素中是否存在 DOM2 级方法。如果存在 DOM2 级方法,则使用该方法:传入事件类型、事件处理程序函数和第三个参数 false(表示冒泡阶段)。如果存在的是 IE 的方法,则采取第二种方案。注意,为了在 IE8 及更早版本中运行,此时的事件类型必须加上”on”前缀。最后一种可能就是使用 DOM0 级方法。

完整代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>跨浏览器兼容</title>
<script type="text/javascript">
window.onload=function(){
    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 btn=document.getElementById("myBtn");
    var handler=function(){
        alert("Clicked");
    };
    EventUtil.addHandler(btn,"click",handler);
    EventUtil.removeHandler(btn,"click",handler);

};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

事件对象:

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

DOM中的事件对象:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>DOM中的事件对象</title>
<script type="text/javascript">
window.onload=function(){
    var btn=document.getElementById("myBtn");
    btn.onclick=function(event){
        alert(event.type);
    };
    btn.addEventListener("click",function(event){
        alert(event.type);
    },false);
};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

这个属性始终都会包含被触发的事件类型,例如”click”(与传入addEventListener()、removeEventListener()中的事件类型一致)。

<input type="button" value="Click Me" onclick="alert(event.type)"/>

以这种方式提供 event 对象,可以让 HTML 特性事件处理程序与 JavaScript 函数执行相同的操作。

event对象包含与创建它的特定事件有关的属性和方法。触发的事件类型不一样,可用的属性和方法也不一样。不过,所有事件都会有下表列出的成员:
技术分享
技术分享

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>DOM中的事件对象</title>
<script type="text/javascript">
window.onload=function(){
    var btn=document.getElementById("myBtn");
    var handler=function(event){
        switch(event.type){
            case "click":
                alert("Clicked");
                break;
            case "mouseover":
                alert("Mouseover");
                break;
            case "mouseout":
                alert("Mouseout");
                break;
        }
    };
    btn.onclick=handler;
    btn.ommouseover=handler;
    btn.onmouseout=handler;

};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

要阻止特定事件的默认行为,可以使用 preventDefault()方法。例如,链接的默认行为就是在被单击时会导航到其 href 特性指定的 URL。如果你想阻止链接导航这一默认行为,那么通过链接的onclick 事件处理程序可以取消它,如下面的例子所示。

var link = document.getElementById("myLink");
link.onclick = function(event){
    event.preventDefault();
};

只有 cancelable 属性设置为 true 的事件,才可以使用 preventDefault()来取消其默认行为。另外, stopPropagation()方法用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡。例如,直接添加到一个按钮的事件处理程序可以调用 stopPropagation(),从而避免触发注册在 document.body 上面的事件处理程序:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>DOM中的事件对象</title>
<script type="text/javascript">
window.onload=function(){
    var btn=document.getElementById("myBtn");
    btn.onclick=function(event){
        alert("Clicked");
        event.stopPropagation();
    };
    document.body.onclick=function(event){
        alert("Body Clicked");
    };
};
</script>
</head>
<body>
    <input type="button" id="myBtn" value="Clicked Me">
</body>
</html>

事件类型:

注意:前面需要加下面这段代码

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;
        }
    }
};

Web 浏览器中可能发生的事件有很多类型。如前所述,不同的事件类型具有不同的信息而“ DOM3级事件”规定了以下几类事件。
? UI(User Interface,用户界面)事件,当用户与页面上的元素交互时触发;
? 焦点事件,当元素获得或失去焦点时触发;
? 鼠标事件,当用户通过鼠标在页面上执行操作时触发;
? 滚轮事件,当使用鼠标滚轮(或类似设备)时触发;
? 文本事件,当在文档中输入文本时触发;
? 键盘事件,当用户通过键盘在页面上执行操作时触发;
? 合成事件,当为 IME(Input Method Editor,输入法编辑器)输入字符时触发;

UI事件:

UI 事件指的是那些不一定与用户操作有关的事件。这些事件在 DOM 规范出现之前,都是以这种或
那种形式存在的,而在 DOM 规范中保留是为了向后兼容。现有的 UI 事件如下。
? DOMActivate:表示元素已经被用户操作(通过鼠标或键盘)激活。这个事件在 DOM3 级事件中被废弃,但 Firefox 2+和 Chrome 支持它。考虑到不同浏览器实现的差异,不建议使用这个事件。
? load:当页面完全加载后在 window 上面触发,当所有框架都加载完毕时在框架集上面触发,当图像加载完毕时在img元素上面触发,或者当嵌入的内容加载完毕时在object元素上面触发。
? unload:当页面完全卸载后在 window 上面触发,当所有框架都卸载后在框架集上面触发,或者当嵌入的内容卸载完毕后在object元素上面触发。
? abort:在用户停止下载过程时,如果嵌入的内容没有加载完,则在object元素上面触发。
? error:当发生 JavaScript 错误时在 window 上面触发,当无法加载图像时在img元素上面触发,当无法加载嵌入内容时在object元素上面触发,或者当有一或多个框架无法加载时在框架集上面触发。后续将继续讨论这个事件。
? select:当用户选择文本框(input或texterea)中的一或多个字符时触发。后续将继续讨论这个事件。
? resize:当窗口或框架的大小变化时在 window 或框架上面触发。
? scroll:当用户滚动带滚动条的元素中的内容时,在该元素上面触发。 body元素中包含所加载页面的滚动条。

load 事件:

<img src="smile.gif" onload="alert(‘Image loaded.‘)">

当图片加载完毕之后进行相应的操作!

var image = document.getElementById("myImage");
EventUtil.addHandler(image, "load", function(event){
    event = EventUtil.getEvent(event);
    alert(EventUtil.getTarget(event).src);
});

unload 事件:

与 load 事件对应的是 unload 事件,这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生 unload 事件。而利用这个事件最多的情况是清除引用,以避免内存泄漏。

resize 事件:

当浏览器窗口被调整到一个新的高度或宽度时,就会触发 resize 事件。这个事件在 window(窗口)上面触发,因此可以通过 JavaScript 或者元素中的 onresize 特性来指定事件处理程序。如

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

scroll 事件:
虽然 scroll 事件是在 window 对象上发生的,但它实际表示的则是页面中相应元素的变化。在混杂模式下,可以通过body元素的 scrollLeft 和 scrollTop 来监控到这一变化;而在标准模式下,除 Safari 之外的所有浏览器都会通过html元素来反映这一变化

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

焦点事件:

焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与document.hasFocus()方法及document.activeElement 属性配合,可以知晓用户在页面上的行踪。有以下 6 个焦点事件。
? blur:在元素失去焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
? DOMFocusIn:在元素获得焦点时触发。这个事件与 HTML 事件 focus 等价,但它冒泡。只有Opera 支持这个事件。 DOM3 级事件废弃了 DOMFocusIn,选择了 focusin。
? DOMFocusOut:在元素失去焦点时触发。这个事件是 HTML 事件 blur 的通用版本。只有 Opera支持这个事件。 DOM3 级事件废弃了 DOMFocusOut,选择了 focusout。
? focus:在元素获得焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
? focusin:在元素获得焦点时触发。这个事件与 HTML 事件 focus 等价,但它冒泡。支持这个事件的浏览器有 IE5.5+、 Safari 5.1+、 Opera 11.5+和 Chrome。
? focusout:在元素失去焦点时触发。这个事件是 HTML 事件 blur 的通用版本。支持这个事件的浏览器有 IE5.5+、 Safari 5.1+、 Opera 11.5+和 Chrome。

IE 的方式最后被 DOM3 级事件采纳为标准方式。
当焦点从页面中的一个元素移动到另一个元素,会依次触发下列事件:
(1) focusout 在失去焦点的元素上触发;
(2) focusin 在获得焦点的元素上触发;
(3) blur 在失去焦点的元素上触发;
(4) DOMFocusOut 在失去焦点的元素上触发;
(5) focus 在获得焦点的元素上触发;
(6) DOMFocusIn 在获得焦点的元素上触发。

其中, blur、 DOMFocusOut 和 focusout 的事件目标是失去焦点的元素;而 focus、 DOMFocusIn和 focusin 的事件目标是获得焦点的元素。

鼠标与滚轮事件:

? click:在用户单击主鼠标按钮(一般是左边的按钮)或者按下回车键时触发。这一点对确保易访问性很重要,意味着 onclick 事件处理程序既可以通过键盘也可以通过鼠标执行。
? dblclick:在用户双击主鼠标按钮(一般是左边的按钮)时触发。从技术上说,这个事件并不是 DOM2 级事件规范中规定的,但鉴于它得到了广泛支持,所以 DOM3 级事件将其纳入了标准。
? mousedown:在用户按下了任意鼠标按钮时触发。不能通过键盘触发这个事件。
? mouseenter:在鼠标光标从元素外部首次移动到元素范围之内时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发。 DOM2 级事件并没有定义这个事件,但 DOM3 级事件将它纳入了规范。 IE、 Firefox 9+和 Opera 支持这个事件。
? mouseleave:在位于元素上方的鼠标光标移动到元素范围之外时触发。这个事件不冒泡,而且
在光标移动到后代元素上不会触发。 DOM2 级事件并没有定义这个事件,但 DOM3 级事件将它纳入了规范。 IE、 Firefox 9+和 Opera 支持这个事件。
? mousemove:当鼠标指针在元素内部移动时重复地触发。不能通过键盘触发这个事件。
? mouseout:在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的另一个元素可能位于前一个元素的外部,也可能是这个元素的子元素。不能通过键盘触发这个事件。
? mouseover:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。不能通过键盘触发这个事件。
? mouseup:在用户释放鼠标按钮时触发。不能通过键盘触发这个事件。

内存和性能:

由于事件处理程序可以为现代 Web 应用程序提供交互能力,因此许多开发人员会不分青红皂白地向页面中添加大量的处理程序。在创建 GUI 的语言(如 C#)中,为 GUI 中的每个按钮添加一个 onclick事件处理程序是司空见惯的事,而且这样做也不会导致什么问题。可是在 JavaScript 中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能。导致这一问题的原因是多方面的。首先,每个函数都是对象,都会占用内存;内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的 DOM 访问次数,会延迟整个页面的交互就绪时间。事实上,从如何利用好事件处理程序的角度出发,还是有一些方法能够提升性能的。

事件委托:

对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。例如, click 事件会一直冒泡到 document 层次。也就是说,我们可以为整个页面指定一个 onclick 事件处理程序,而不必给每个可单击的元素分别添加事件处理程序。

照理来说,实现多种点击效果,我们应该做成以下这样的形式,:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>内存和性能</title>
<script type="text/javascript">
window.onload=function(){
    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 item1 = document.getElementById("goSomewhere");
    var item2 = document.getElementById("doSomething");
    var item3 = document.getElementById("sayHi");
    EventUtil.addHandler(item1, "click", function(event){
        location.href = http://www.mamicode.com/"http://www.wrox.com";
    });
    EventUtil.addHandler(item2, "click", function(event){
        document.title = "I changed the document‘s title";
    });
    EventUtil.addHandler(item3, "click", function(event){
        alert("hi");
    });
};

</script>
</head>
<body>
    <ul id="myLinks">
        <li id="goSomewhere">
            Go somewhere
        </li>
        <li id="doSomewhere">
            Do somewhere
        </li>
        <li id="sayHi">
            Say hi
        </li>
    </ul>
</body>
</html>

但是这样会出现错误,所以我们引入了事件委托:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>事件委托</title>
<script type="text/javascript">
window.onload=function(){
    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;
            }
        },

        getEvent: function (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 = http://www.mamicode.com/false;
            }
        },
        stopPropagation: function (event) {
            if (event.stopPropagation) {
                event.stopPropagation();
            } else {
                event.cancelBubbles = true;
            }
        },
        getRelatedTarget: function (event) {
            if (event.relatedTarger) {
                return event.relatedTarget;
            } else if (event.toElement) {
                return event.toElement;
            } else if (event.fromElement) {
                return event.fromElement;
            } else { return null; }

        }

    };
    var list=document.getElementById("myLinks");

    EventUtil.addHandler(list,"click",function(event){
        event=EventUtil.getEvent(event);
        var target=EventUtil.getTarget(event);
        switch(target.id){
            case "doSomewhere":
                document.title="I LOVE CHINA.";
                break;
            case "goSomewhere":
                location.href=http://www.mamicode.com/"http://www.baidu.com";
                break;
            case "sayHi":
                alert("Hi");
                break;
        }
    });
};
</script>
</head>
<body>
    <ul id="myLinks">
        <li id="goSomewhere">
            Go somewhere
        </li>
        <li id="doSomewhere">
            Do somewhere
        </li>
        <li id="sayHi">
            Say hi
        </li>
    </ul>
</body>
</html>

与前面未使用事件委托的代码比一比,会发现这段代码的事前消耗更低,因为只取得了一个 DOM 元素,只添加了一个事件处理程序。虽然对用户来说最终的结果相同,但这种技术需要占用的内存更少。所有用到按钮的事件(多数鼠标事件和键盘事件)都适合采用事件委托技术。

移除事件处理程序:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>移除事件处理程序</title>
<script type="text/javascript">

</script>
</head>
<body>
    <div id="myDiv">
        <input type="button" value="Click Me" id="myBtn">
    </div>
    <script type="text/javascript">
    var btn=document.getElementById("myBtn");
    btn.onclick=function(){
        btn.onclick=null;//移出事件处理程序
        document.getElementById("myDiv").innerHTML="Processing";
    };
    </script>
</body>
</html>
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

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