JavaScript中的事件
JavaScript和HTML之间的交互是通过用户和浏览器操作页面时引发的事件(event)来处理的。
事件是DOM(文档对象模型)的一部分。
事件流:事件流意味着在页面上可有不仅一个,甚至多个元素响应同一个事件。事件发生顺序(事件流)是IE和Netscape在事件支持上的主要差别。
冒泡型事件
IE上的解决方案是绰号为冒泡(dubbed bubbling)的技术。冒泡型事件的基本思想是,事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。
捕获型事件(event capturing)的解决方案。事件的捕获和冒泡刚好是相反的两种过程——捕获型事件中,事件从最不精确的对象(document对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)。又被称之为自顶向下的事件模型,因为它是从DOM层次的顶端开始向下延伸的。
DOM事件流
DOM同时支持两种事件模型:捕获型事件和冒泡型事件,但是捕获型事件先发生。
事件处理函数/监听函数
用于响应某个事件而调用的函数称为事件处理函数(event handler),或者DOM称之为事件监听函数(event Listener).
分配事件处理函数,如:
<script>
var oV = document.getElementById("ov");
oV.onclick = function() {
alert("I was clicked!");
};
</script>
1、IE
在IE中,每个元素和window对象都有两个方法:attachEvent()和detachEvent().
attachEvent()用来给一个事件附加事件正理函数,而detachEvent()用来将事件处理函数分离出来。每个方法都有两个参数:要分配的事件处理函数的名字(如:onclick)及一个函数。
[Object].attachEvent("name_of_event_handler",fnHandler);
[Object].detachEvent("name_of_event_handler",fnHandler);
在attacheEvent()中,函数被作为事件处理函数添加,detachEvent()事件处理函数列表中查找制定的函数,并移除它。例:
var fnClick = function() {
alert("clicked");
};
var oDiv = document.getElementById("myDiv");
oDiv.attachEvent("onclick", fnClick); //add the event handler
oDiv.detachEvent("onclick", fnClick); //remove the event handler
这种方法可用来添加多个事件处理函数:
var fnClick1 = function()
{
alert("Clicked!");
};
var fnClick2 = function()
{
alert(Also clicked!);
};
var oDiv = document.getElementById("div");
oDiv.attachEvent("onclick",fnClick1);
oDiv.attachEvent("onclick",fnClick2);
2、DOM
DOM方法addEventListener()和removeEventListener()用来分配和移除事件处理函数。与IE不同,这些方法需要三个参数:事件名称,要分配的函数和处理函数是用于冒泡阶段学是捕获阶段。如果事件处理函数是用于捕获阶段,第三个参数为true;用于冒泡阶段,则为false。下面是语法:
[Object].addEventListener("name_of_event",fnHandler,bCapture);
[Object].removeEventListener("name_of_event",fnHandler,bCapture);
要使用这些方法,首先获取要处理的对象的引用,然后分配或删除事件处理函数:
var fnClick = function()
{
alert("Clicked!");
};
var oDiv = document.getElementById("div1");
oDiv.addEventListener("click",fnClick,false); //add the event handler
oDiv.removeEventListener("click",fnClick,false); //remove the event handler
与IE中一样,可附加多个事件处理函数。
事件对象
会创建关于刚刚发生的事件的信息的事件对象,包含的信息如下:
引起事件的对象;
事件发生时鼠标的信息;
事件发生的键盘的信息。
1、定位
在IE中,事件对象是window对象的一个属性event. 也就是说,事件处理函数必须这样访问事件对象:
oDiv.onclick = function()
{
var oEvent = window.event;
};
DOM标准则说,event对象必须作为唯一的参数传给事件处理函数。
2、属性/方法
3、相似性
1、获取事件类型
在任何一种浏览器中获取事件的类型:var sType = oEvent.type;
它返回类似"click "或"mouseover"之类的值,当某个函数同时为两个事件的处理函数时,这很有用。
function handleEvent(oEvent)
{
if(oEvent.type == "click")
{
alert("Clicked!");
}
else if(oEvent.type == "mouseover")
{
alert("Mouse Over!");
}
}
oDiv.onclick = handleEvent;
oDiv.onmouseover = handleEvent;
2、获取按键代码(keydown/keyup事件)
在keydown或者keyup事件中,可使用keyCode属性获取按下的按键的数值代码:
var iKeyCode = oEvent.keyCode;
keyCode属性总包含代表按下按键的一个代码,它可能代表一个字符,也可能不是。例:Enter(回车)键的keyCode为13,空格键的keyCode为32,回退(BackSpace)键的keyCode为8.
3、检测Shift、Alt、Ctrl键
检测Shift、Alt、Ctrl键是否被按下,IE和DOM都可以使用以下代码:
var bShift = oEvent.shiftKey;
var bAlt = oEvent.altKey;
var bCtrl = oEvent.ctrlKey;
4、获取客户端坐标
在鼠标事件中,可用clientX和clientY属性获取鼠标指针在客户端区域的位置:
var iClientX = oEvent.clientX;
var iClientY = oEvent.clientY;
4、区别
1、获取目标
在IE中,目标包含在event对象的srcElement属性中:
var oTarget = oEvent.srcElement;
Macintosh上的IE同时支持srcElement和target属性。
在DOM兼容的浏览器中,目标包含在target属性中:
var oTarget = oEvent.target;
IE目标只能是元素、文档或者窗口;DOM兼容的浏览器也允许把文本节点作为目标。
2、获取字符代码
如果按键代表一个字符(非Shift、Ctrl、Alt等),IE的keyCode将返回字符的代码(等于它的Unicode值):var iCharCode = oEvent.keyCode;
在DOM兼容的浏览器中,按键的代码和字符会有一个分离。要获取字符代码,使用charCode属性:var iCharCode = oEvent.charCode;
然后可用这个值来获取实际的字符,只要使用String.fromCharCode()方法:
var sChar = String.fromCharCode(oEvent.charCode);
如果不确定按下的按键是否包含字符,则可使用isChar属性来进行判断:
if(oEvent.isChar)
{
var iCharCode = oEvent.charCode;
}
3、阻止某个事件的默认行为
在IE中要阻止某个事件的默认行为,必须将returnValue属性设置为false:
oEvent.returnValue = false;
而在Mozilla中,只要调用preventDefault()方法:
oEvent.preventDefult();
第一、当用户右键点击页面时,阻止他使用上下文菜单。你只要阻止contextmenu事件的默认行为就可以了:
document.body.oncontextmenu = function(oEvent)
{
if(isIE)
{
oEvent = window.event;
oEvent.returnValue = false;
}
else
{
oEvent.preventDefault();
}
}
第二、你可能还相在为文本框键入字符时,阻止它的默认行为,以禁止特定字符的输入或者抢先阻止鼠标的动作,除非满足特定的条件。这是非常强大的功能。
4、停止事件复制(冒泡)
在IE中,要阻止事件进一步冒泡,必须设置cancelBubble属性为true:
oEvent.cancelBubble = true;
在mozilla中,只需调用stopPropagation()方法:oEvent.stopPropagation();
停止事件复制可以阻止事件流中的其他对象的事件处理函数的执行。考虑这个例子:
<html onclick = "alert('html')">
<body onclick = "alert('body')">
<input type = "button" value = "click Me" onclick="alert('input')"/>
</body>
</html>
事件的类型
根据触发事件的事物和事件发生的对象,可将浏览器中发生的事件分成几个类型。DOM标准定义了以下几组事件:
鼠标事件:用户使用鼠标进行特定操作时触发;
键盘事件:用户在键盘上敲击、输入时触发;
HTML事件:窗口发生应运或者发生特定的客户端-服务器端交互时触发;
突变事件:底层的DOM结构发生改变时触发。
1、鼠标事件
click:用户点击鼠标左键时发生(如果右键也按下则不会发生)。当用户的焦点在按钮上,并按了回车键,同样会触发这个事件。
dblclick:用户双击鼠标左键时发生(如果右键也按下则不会发生)。
mousedown:用户点击任意一个鼠标按钮时发生。
mouseout:鼠标指针在某个元素上,且用户正要将其移出元素的边界时发生。
mouseover:鼠标移出某个元素,到另一个元素上时发生。
mouseup:用户松开任意一个按钮时发生。
mousemove:鼠标在某个元素上时持续发生。
使用mouseover和mouseout事件改变页面上某个东西的外观的一个很流行的方法。如某个图片:
<img src="image1.gif" onmouseover="this.src='image2.gif'" onmouseout="this.src='image1.gif'"/>
1、事件的属性
每个鼠标事件都会给以下event蝗属性填入值:
坐标属性(例如clientX和clientY等);
type属性;
target(DOM)或srcElement(IE)属性;
shiftKey、ctrlKey、altKey和metaKey(DoM)属性;
button属性(只在mousedown、mouseover、mouseout、mousemove和mouseup事件中)。将其他属性也加入到事件处理中去,就可以描绘出对刚刚发生的事件的更加完整的图像:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
function handleEvent(oEvent) {
var oTextBox = document.getElementById("txt1");
oTextBox.value += "\n>" + oEvent.type;
oTextBox.value += "\n target is " + (oEvent.target || oEvent.srcElement).id;
oTextBox.value += "\n at (" + oEvent.clientX + "," + oEvent.clientY + ") on the client";
oTextBox.value += "\n at (" + oEvent.screenX + "," + oEvent.screenY + ") on the screen";
oTextBox.value += "\n button down is " + oEvent.button;
var arrKeys = [];
if (oEvent.shiftKey) {
arrKeys.push("Shift");
}
if (oEvent.ctrlKey) {
arrKeys.push("Ctrl");
}
if (oEvent.altKey) {
arrKeys.push("Alt");
}
oTextBox.value += "\n keys down are " + arrKeys;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<p>Use your mouse to click and double click the red square.</p>
<div style="width:100px;height:100px;background-color:Red" id = "div1" onmouseover="handleEvent(event)" onmouseout="handleEvent(event)" onmousedown="handleEvent(event)" onmouseup="handleEvent(event)" ondblclick="handleEvent(event)" onkeydown="handleEvent(event)" onkeypress="handleEvent(event)" onkeyup="handleEvent(event)">
</div>
<p><textarea id="txt1" rows="15" cols="50"></textarea></p>
</form>
</body>
</html>
对于mouseover和mouseout事件,事件对象还有额外的属性。在IE中,fromElement属性包含鼠标指针来自的元素,同时toElement包含鼠标指针去往的元素。对于mouseover事件,toElement总是等于srcElement,而对于mouseout事件,fromElement总是等于srcElement.
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>IE Mouse Events Example</title>
<script type="text/javascript">
function handleEvent(oEvent) {
var oTextbox = document.getElementById("txt1");
oTextbox.value += "\n>" + oEvent.type;
oTextbox.value += "\n target is " + oEvent.srcElement.tagName;
if (oEvent.fromElement) {
oTextbox.value += "\n fromElement is " + oEvent.fromElement.tagName;
if (oEvent.toElement) {
oTextbox.value += "\n toElement is " + oEvent.toElement.tagName;
}
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<p>Use your mouse to click and double click the red square.</p>
<div style="width:100px;height:100px;background-color:Red" id = "div1" onmouseover="handleEvent(event)" onmouseout="handleEvent(event)" onmousedown="handleEvent(event)" onmouseup="handleEvent(event)" ondblclick="handleEvent(event)" onkeydown="handleEvent(event)" onkeypress="handleEvent(event)" onkeyup="handleEvent(event)">
</div>
<p><textarea onkeydown="handleEvent(event)" onkeyup="handleEvent(event)" id="txt1" rows="15" cols="50"></textarea></p>
</form>
</body>
</html>
DOM对mouseover和mouseout只支持一个event属性relatedTarget.在mouseover事件中,relatedTarget指出鼠标指针来自何处。在mouseout事件中,relatedTarget指出鼠标指针去往何方。
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>DOM Mouse Events Example</title>
<script type="text/javascript">
function handleEvent(oEvent) {
var oTextbox = document.getElementById("txt1");
oTextbox.value += "\n>" + oEvent.type;
oTextbox.value += "\n target is " + oEvent.target.tagName;
oTextbox.value += "\n relatedTarget is " + oEvent.relatedTarget.tagName;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<p>Use your mouse to click and double click the red square.</p>
<div style="width:100px;height:100px;background-color:Red" id = "div1" onmouseover="handleEvent(event)" onmouseout="handleEvent(event)" onmousedown="handleEvent(event)" onmouseup="handleEvent(event)" ondblclick="handleEvent(event)" onkeydown="handleEvent(event)" onkeypress="handleEvent(event)" onkeyup="handleEvent(event)">
</div>
<p><textarea onkeydown="handleEvent(event)" onkeyup="handleEvent(event)" id="txt1" rows="15" cols="50"></textarea></p>
</form>
</body>
</html>
2、顺序
click事件触发前,会先发生mousedown事件,然后发生mouseup事件。类似的,要触发dblclick事件,在同一个目标上要按顺序发生以下事件:
(1)mousedown;
(2)mouseup;
(3)click;
(4)mousedown;
(5)mouseup;
(6)click;
(7)dblclick;
2、键盘事件
keydown:用户在键盘上按下某按键时发生。一直按着某按键,它则会不断触发(Opera浏览器除外)。
keypress:用户按下一个按键,并产生一个字符时发生。一直按下按键时,它则会持续发生。
keyup:用户释放按着的按键时发生。
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Key Events Example</title>
<script type="text/javascript">
function handleEvent(oEvent) {
var oTextbox = document.getElementById("txt1");
oTextbox.value += "\n>" + oEvent.type;
}
</script>
</head>
<body>
<p>Type some characters into the first textbox.</p>
<p><textarea id="txt1" rows="15" cols="50" onkeydown="handleEvent(event)" onkeyup="handleEvent(event)" onkeypress="handleEvent(event)"></textarea></p>
</body>
</html>
1、事件的属性
keyCode属性;
charCode属性(仅DOM);
target(DOM)或者srcElement(IE)属性;
shiftKey、ctrlKey、altKey和metaKey(DOM)属性。
2、顺序
用户按一次某字符按键时,会按以下顺序发生事件:
(1)keydown;
(1)keypress;
(2)keyup;
如果用户按一次某非字符按键(如Shift),会按以下顺序发生事件:
(1)keydown;
(2)keyup.
如果用户按下一个字符按键且不放,keydown和keypress事件将逐个持续触发,直到松开按键;如果用户按下非字符按键且不放,将只有keydown事件持续触发。
3、HTML事件
load事件:页面完全载入后,在window对象上触发;
unload事件:页面完全卸载后,在window对象上触发;
abort事件:用户停止下载过程时,如果<object/>对象还未完全载入,就在其上触发;
error事件:JavaScript脚本出错时,在window对象上触发;某个<img/>的指定图像无法载入时,在其上触发;或<object/>元素无法载入时触发;或者框架集中的一个或多个框架无法载入时触发。
select事件:用户选择了文本框中的一个或多个字符时触发(<input/>或者<textarea/>)。
change事件:文本框失去焦点时并且在它获取焦点后内容发生过改变时触发;某个<select/>元素的值发生改变时触发。
submit事件:点击提交按钮时,在<from/>上触发。
reset事件:点击重置按钮时,在<from/>上触发。
resize事件:窗口或者框架的大小发生改变时触发。
scroll事件:用户在任何带流动条的元素上卷动它时触发。<body/>元素包含载入页面的滚动条。
focus事件:任何元素或者窗口本身获取焦点时触发。
blur事件:任何元素或者窗口本身失去焦点时触发。
1、load和unload事件
在全部的页面载入完之前,任何DOM操作都不能发生。在window对象可用两种方法定义onload事件处理函数。首先,可使用JavaScript直接将其分配给window对象:
<script type="text/javascript">
window.onload = function() {
alert("Loaded");
}
</script>
卸载事件在你从一个页面浏览到另外一个页面时(通过点击一个链接或者使用前进/后退按钮)或者关闭浏览器窗口时触发:
<body onload="alert("GoodBey!")">
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
2、resize事件
在网页需要根据浏览器窗口的大小进行调整时,可用resize事件来判断何时动态地改变某些元素。
3、Scroll事件
当你希望在用户卷动窗口(或其它元素)时,跟踪变化来确保某些内容一直在屏幕上可见。通过scroll事件即可实现:
<body onscroll="alert('Scrolling')">
<p>Try scrolling this window.</p>
</body>
也可以把事件处理函数分配给window.onscroll属性:
<head>
<script>
window.onscroll = function()
{
alert("scrolling");
}
</script>
</head>
<body>
<p>Try scrolling this window.</p>
<p></p>
</body>
也可和<body/>元素的一些属性协调使用这个事件,如scrollLeft,它保存窗口在水平方向上卷动距离,以及scrollTop,它保存窗口在垂直方向上卷动的距离:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>OnScroll Example</title>
<script type="text/javascript">
window.onscroll = function() {
var oTextbox = document.getElementById("txt1");
oTextbox.value += "\nScroll is at " + document.body.scrollLeft + "horizontally and " + document.body.scrollTop + " vertically.";
}
</script>
</head>
<body>
<p>Try scrolling this window.</p>
<p><textarea rows="15" cols="50" id="txt1"></textarea></p>
<p></p>
<p></p>
</body>
</html>
始终在页面的顶部显示的水印,例:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>OnScroll Example</title>
<script type="text/javascript">
window.onscroll = function() {
var oWatermark = document.getElementById("divWatermark");
oWatermark.style.top = document.body.scrollTop;
}
</script>
</head>
<body>
<p>Try scrolling this window.</p>
<div id="divWatermark" style="position:absolute;top:0px;right:0px;color:#CCCCCC;width:150px;height:30px;background-color:Navy">
Watermark
</div>
<p>Line 1</p>
<p>Line 2</p>
<p>Line 3</p>
<p>Line 4</p>
<p>Line 5</p>
<p>Line 6</p>
<p>Line 7</p>
<p>Line 8</p>
<p>Line 9</p>
</body>
</html>
跨平台的事件
EventUtil对象:容器对象
添加/删除事件处理函数
IE用attachEvent()方法为元素分配任意数目的事件处理函数,而DOM则用addEventListener()方法。所以,第一个EventUtil对象的方法就是创建一个统一的分配事件处理函数的方式,我们称其为addEventHandler()(这样不会与任何浏览器的实现相混淆)。这个方法有三个参数:要分配事件处理函数的对象,要处理的事件的名称以及要分配的函数。在方法内部,使用了一个简单的检测算法以在正确的时间地点使用正确的功能:
<script>
EventUtil.addEventHandler = function(oTarget, sEventType, fnHandler) {
if (oTarget.addEventListener) {
oTarget.addEventListener(sEventType, fnHandler, false);
}
else if (oTarget.attachEvent) {
oTarget.attachEvent("on" + sEventType, fnHandler);
}
else {
oTarget["on" + sEventType] = fnHandler;
}
}
</script>
removeEventHandler()删除事件处理函数方法,这个函数接受和addEventHandler()一样的参数。
<script>
EventUtil.removeEventHandler = function(oTarget, sEventType, fnHadler) {
if (oTarget.removeEventHandler) {
oTarget.removeEventListener(sEventType, fnHadler, false);
}
else if (oTarget.detachEvent) {
oTarget.detachEvent("on" + sEventType, fnHadler);
else
{
oTarget["on" + sEventType] = null;
}
}
}
</script>
下面的例子展示这些用法:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Add/Remove Event Handlers Example</title>
<script type="text/javascript">
var EventUtil = new Object;
EventUtil.addEventHandler = function(oTarget, sEventType, fnHandler) {
if (oTarget.addEventListener) {
oTarget.addEventListener(sEventType, fnHandler, false);
}
else if (oTarget.attachEvent) {
oTarget.attachEvent("on" + sEventType, fnHandler);
}
else {
oTarget["on" + sEventType] = fnHandler;
}
};
EventUtil.removeEventHandler = function(oTarget, sEventType, fnHadler) {
if (oTarget.removeEventHandler) {
oTarget.removeEventListener(sEventType, fnHadler, false);
}
else if (oTarget.detachEvent) {
oTarget.detachEvent("on" + sEventType, fnHadler);
}
else {
oTarget["on" + sEventType] = null;
}
};
function handleClick() {
alert("Click!");
var oDiv = document.getElementById("div1");
EventUtil.removeEventHandler(oDiv, "click", handleClick);
}
window.onload = function() {
var oDiv = document.getElementById("div1");
EventUtil.addEventHandler(oDiv, "click", handleClick);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div id="div1" style="background-color:Red;width:100px;height:100px">
</div>
</form>
</body>
</html>
3、格式化event对象
首先,给EventUtil定义一个新方法formatEvent(),它可以接受一个参数,也就是event对象:
EventUtil.formatEvent = function(oEvent) {
if (isIE && isWin) {
oEvent.charCode = (oEvent.type == "keypress") ? oEvent.keyCode : 0;
oEvent.eventPhase = 2;
oEvent.isChar = (oEvent.charCode > 0);
oEvent.pagex = oEvent.clientX + document.body.scrollLeft;
oEvent.pageY = oEvent.clientY + document.body.scrollTop;
oEvent.preventDefault = function() {
this.returnValue = false;
};
if (oEvent.type == "mouseout") {
oEvent.relatedTarget = oEvent.toElement;
}
else if (oEvent.type == "mouseover") {
oEvent.relatedTarget = oEvent.fromElement;
}
oEvent.stopPropagation = function() {
this.cancelBubble = true;
};
oEvent.target = oEvent.srcElement;
oEvent.time = (new Date()).getTime();
}
return oEvent;
}
4、获取事件对象
处理IE,我们检查window.event是否存在,然后在返回事件对象前用formatEvent()方法格式化它。
EventUtil.getEvent = function()
{
if(window.event)
{
return this.formatEvent(window.event);
}
};
处理DOM的情况,DOM兼容的浏览器是event对象作为参数传递给事件处理函数的。函数其实也是一个对象,也是属性。可以访问事件处理函数的argument[0]来获取event对象:
EventUtil.getEvent = function()
{
if(window.event)
{
return this.formatEvent(window.event);
}
else
{
return EventUtil.getEvent.caller.arguments[0];
}
}
5、示例
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Mouse Events Example</title>
<script type="text/javascript" src="detect.js">
</script>
<script type="text/javascript" src="eventutil.js"></script>
<script type="text/javascript">
var EventUtil = new Object;
EventUtil.addEventHandler(window, "load", function() {
var oDiv = document.getElementById("div1");
EventUtil.addEventHandler(oDiv, "mouseover", handleEvent);
EventUtil.addEventHandler(oDiv, "mouseout", handleEvent);
EventUtil.addEventHandler(oDiv, "mousedown", handleEvent);
EventUtil.addEventHandler(oDiv, "mouseup", handleEvent);
EventUtil.addEventHandler(oDiv, "click", handleEvent);
EventUtil.addEventHandler(oDiv, "dblclick", handleEvent);
});
function handleEvent() {
var oEvent = EventUtil.getEvent();
var oTextbox = document.getElementById("txt1");
oTextbox.value += "\n>" + oEvent.type;
oTextbox.value += "\n target is " + oEvent.target.tagName;
if (oEvent.relatedTarget) {
oTextbox.value += "\n relatedTarget is " + oEvent.relatedTarget.tagName;
}
}
</script>
</head>
<body>
<p>Use your mouse to click and double click the red square.</p>
<div style="width:100px;height:100px;background-color:red" id="div1">
</div>
<p><textarea id="txt1" rows="15" cols="50"></textarea></p>
</body>
</html>