8.1 处理窗口事件
当用户执行某些会影响整个浏览器窗口的操作时,就会发生窗口事件。最常见的窗口事件是通过打开某个网页来加载窗口。还有在窗口关闭、移动或转到后台时触发事件处理程序的事件。在使用事件处理程序时,常常会发现使用点号语法将事件处理程序与一个对象连接起来是有意义的,如下所示:
window.onfocus
window.onload
document.onmousedown
注意,像这样将事件处理程序作为对象的一部分使用时,事件处理程序的名称是全小写的。另外,更符合标准的做法是,将事件处理程序放在外部脚本而不是 HTML 标签中,这样可以将 JavaScript 代码与 HTML 代码分隔开,而且在一个外部文件中编辑(或替换)所有 JavaScript 代码会更容易。
8.1.1 onload事件
当用户进入页面而且所有页面元素都完成加载时,就会触发这个事件。
多重 onload 示例的 HTML
<!DOCTYPE html>
<html>
<head>
<title>Welcome!</title>
<script src="script01.js"></script>
</head>
<body id="pageBody">
<h1>Welcome to our Web site!</h1>
</body>
</html>
addOnload(initOne);
addOnload(initTwo);
addOnload(initThree);
function addOnload(newFunction) {
var oldOnload = window.onload;
if (typeof oldOnload == "function") {
window.onload = function() {
oldOnload();
newFunction();
}
}
else {
window.onload = newFunction;
}
}
function initOne() {
document.getElementById("pageBody").style.backgroundColor = "#00F";
}
function initTwo() {
document.getElementById("pageBody").style.color = "#F00";
}
function initThree() {
var allTags = document.getElementById("PageBoby")getElementsByTagName("*");
for (var i=0; i<allTags.length; i++) {
if (allTags[i].nodeName == "H1") {
allTags[i].style.border = "5px green solid";
allTags[i].style.padding = "25px";
allTags[i].style.backgroundColor = "#FFF";
}
}
}
1. addOnload(initOne);
addOnload(initTwo);
addOnload(initThree);
8.1.2 onunload事件
当用户离开网页时,就会触发 onunload 事件处理程序。这个事件最常见的用途是,当用户离开某些商业站点(尤其是色情站点)时弹出广告窗口。如果你访问色情站点的话,常常会发现几乎不可能离开——每当你试图关闭窗口或导航到别处时,都会出现一个接一个的窗口,重新打开同样的页面或同类的其他页面。因此,用户非常讨厌 onunload 处理程序,所以使用它时要慎重。
8.1.3 onbeforeunload事件
onbeforeunload在用户开始离开页面之前触发,而 onunload 在用户离开页面之后触发。
<!DOCTYPE html>
<html>
<head>
<title>FabulousAirTickets.com</title>
<script src="script02.js"></script>
</head>
<body>
<h2>FabulousAirTickets.com</h2>
<form action="#">
<p>
<label for="from">From:</label>
<input type="text" id="from">
<label for="to">To:</label>
<input type="text" id="to">
</p>
<p>
<label for="leavedate">DepartureDate:</label>
<input type="date" id="leavedate">
<label for="returndate">ReturnDate:</label>
<input type="date" id="returndate">
</p>
<p>
# of Adults:
<select>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</p>
<p>
<input type="submit" value="Find Flights!">
<input type="reset">
</p>
</form>
</body>
</html>
window.onbeforeunload = function() {
return "If you close this window, your flight choices will be lost!";
}
如果他们离开表单,之前输入的所有信息都会丢失。如果用 onunload来实现这个功能,用户之前输入的信息就全没了;但是因为这里使用的是 onbeforeunload,用户就有机会决定是否放弃之前输入的信息。
8.1.4 onresize事件
当窗口调整大小时,会触发 onresize 事件处理程序。
8.1.5 onmove事件
当窗口移动时,会触发 onmove 事件处理程序。
8.1.6 onabort事件
当用户取消网页上的图像加载时,会触发 onabort 事件处理程序。这种事件不太常用,而且并非所有浏览器都支持它。
8.1.7 onerror事件
当页面上发生 JavaScript 错误时,可能会触发 onerror 事件处理程序。
8.1.8 onfocus事件和onblur事件
onfocus 和 onblur 事件处理程序互为镜像,听起来就像现实中你在 JavaScript 程序上奋战到午夜一样。当一个页面成为最前面的活动窗口时,就会触发 onfocus 处理程序;而当一个页面退回后台的时候,就会触发 onblur 事件处理程序。由于这两个事件处理程序老是被滥用,大多数现代浏览器已经不支持它们了。
8.1.9 onscroll事件
当用户向上或者向下滚动页面时,就会触发 onscroll 事件。
8.1.10 onDOMContentLoaded事件
onDOMContentLoaded 跟 onload 类似,只是它是在页面自身完成加载时被触发,而不是一些相关文件(如图片)完成加载时被触发。
8.2 处理鼠标事件
8.2.1 onmousedown事件
<!DOCTYPE html>
<html>
<head>
<title>onMousedown capture</title>
<script src="script03.js"></script>
</head>
<body>
<h1>Important source data that someone might want to look at.</h1>
</body>
</html>
if (typeof document.oncontextmenu == "object") {
if (document.all) {
document.onmousedown = captureMousedown;
}
else {
document.oncontextmenu = captureMousedown;
}
}
else {
window.oncontextmenu = captureMousedown;
}
function captureMousedown(evt) {
if (evt) {
var mouseClick = evt.which;
}
else {
var mouseClick = window.event.button;
}
if (mouseClick==1 || mouseClick==3) {
alert("Menu Disabled");
return false;
}
}
8.2.2 onmouseup事件
与 onmousedown 事件相似, onmouseup 事件会在用户单击鼠标然后释放按钮时触发。
8.2.3 onmousemove事件
当页面的访问者移动鼠标时,就会触发 onmousemove 事件。
<!DOCTYPE html>
<html>
<head>
<title>Mouse Movements</title>
<link rel="stylesheet" href="script04.css">
<script src="script04.js"></script>
</head>
<body>
<img src="images/circle.gif" alt="left eye" id="lEye">
<img src="images/circle.gif" alt="right eye" id="rEye">
<img src="images/lilRed.gif" alt="left eyeball" id="lDot">
<img src="images/lilRed.gif" alt="right eyeball" id="rDot">
</body>
</html>
body {
background-color: #FFF;
}
#lEye, #rEye {
position: absolute;
top: 100px;
width: 24px;
height: 25px;
}
#lDot, #rDot {
position: absolute;
top: 113px;
width: 4px;
height: 4px;
}
#lEye {
left: 100px;
}
#rEye {
left: 150px;
}
#lDot {
left: 118px;
}
#rDot {
left: 153px;
}
document.onmousemove = moveHandler;
function moveHandler(evt) {
if (!evt) {
evt = window.event;
}
animateEyes(evt.clientX, evt.clientY);
}
function animateEyes(xPos,yPos) {
var rightEye = document.getElementById("rEye");
var leftEye = document.getElementById("lEye");
var rightEyeball = document.getElementById("rDot").style;
var leftEyeball = document.getElementById("lDot").style;
leftEyeball.left = newEyeballPos(xPos, leftEye.offsetLeft);
leftEyeball.top = newEyeballPos(yPos, leftEye.offsetTop);
rightEyeball.left = newEyeballPos(xPos, rightEye.offsetLeft);
rightEyeball.top = newEyeballPos(yPos, rightEye.offsetTop);
function newEyeballPos(currPos,eyePos) {
return Math.min(Math.max(currPos,eyePos+3), eyePos+17) + "px";
}
}
8.2.4 onmouseover事件
现在,你应该很熟悉这个事件了:我们曾经利用它实现图像翻转器。当鼠标移动进任何注册了onmouseover 事件处理程序的区域时,就会触发这个事件。
8.2.5 onmouseout事件
毫无疑问,既然有 onmouseover,当然也有对应的 onmouseout。当鼠标离开一个注册了此事件的区域时,就会触发这个事件。
8.2.6 ondblclick事件
因特网的缺点之一是,计算机用户已经习惯的用户界面元素在 Web 上改变了。例如,计算机新用户最早学习的操作就是用鼠标进行双击,但是在 Web 上没有双击操作,至少不曾有过。
<!DOCTYPE html>
<html>
<head>
<title>Image Popup</title>
<link rel="stylesheet" href="script05.css">
<script src="script05.js"></script>
</head>
<body>
<h3>Double-click on an image to see the full-size version</h3>
<img src="images/Img0_thumb.jpg" alt="Thumbnail 0" id="Img0">
<img src="images/Img1_thumb.jpg" alt="Thumbnail 1" id="Img1">
<img src="images/Img2_thumb.jpg" alt="Thumbnail 2" id="Img2">
</body>
</html>
body {
background-color: #FFF;
}
img {
margin: 0 10px;
border: 3px #00F solid;
width: 160px;
height: 120px;
}
window.onload = initImages;
function initImages() {
for (var i=0; i<document.images.length;i++) {
document.images[i].ondblclick = newWindow;
}
}
function newWindow() {
var imgName = "images/" + this.id + ".jpg"
var imgWindow = window.open(imgName,"imgWin", "width=320,height=240,scrollbars=no")
}
8.2.7 onclick事件
onclick 处理程序的工作方式与 ondblclick 处理程序相似,差异仅仅是由单击触发它,而不是双击触发。 onmouseup 处理程序也相似,差异是 onclick 要求用户按下鼠标按钮并放开才能触发,而onmouseup 只需要后者。
8.3 表单事件处理
表单事件处理主要用来验证表单。通过使用下面列出的事件,可以处理用户在表单上所做的任何操作。
8.3.1 onsubmit事件
当用户单击 Submit 按钮来提交表单时,就会触发 onsubmit 处理程序。另外,根据浏览器的不同,当用户退出表单上的最后一个文本输入字段时,也可能会触发它。如果脚本包含onsubmit 处理程序,而且这个处理程序的结果是 false,那么表单就不会发送回服务器。
8.3.2 onreset事件
当用户单击表单上的 Reset 按钮(如果有这个按钮的话)时,就会触发 onreset 处理程序。如果表单具有在加载页面时设置的默认值,这会非常方便——如果用户单击 Reset 按钮,就需要用脚本动态地重新设置默认值。
8.3.3 onchange事件
如脚本 6-3 所示,当用户修改表单字段时,就会触发 onchange 事件处理程序。这可以用来立即验证输入的信息,或者在用户单击 Submit 按钮之前对用户的选择作出响应。
8.3.4 onselect事件
如果用户选择了一个 input 或 textarea 表单区域中的文本,就会触发 onselect 处理程序。
8.3.5 onclick事件
8.2 节提到了 onclick 处理程序,这里再次提到它是因为在处理表单时经常会用到它。当用户单击复选框或单选按钮时,就会触发这个事件。
8.3.6 onblur事件
onblur 事件可以用于浏览器窗口(如前面所示),也经常用在表单上。
<!DOCTYPE html>
<html>
<head>
<title>Requiring an entry</title>
<link rel="stylesheet" href="script06.css">
<script src="script06.js"></script>
</head>
<body>
<form action="#">
<h3>
Email address: <input type="text" class="reqd"><br><br>
Name (optional): <input type="text">
</h3>
</form>
</body>
</html>
body {
background-color: #FFF;
}
.highlight {
background-color: #FF9;
}
window.onload = initForm;
function initForm() {
var allTags = document.forms[0].getElementsByTagName("*");
for (var i=0; i<allTags.length; i++) {
if (allTags[i].className.indexOf("reqd") > -1) {
allTags[i].onblur = fieldCheck;
}
}
}
function fieldCheck() {
if (this.value == "") {
this.className += " highlight";
this.focus();
}
else {
this.className = "reqd";
}
}
8.3.7 onfocus事件
有时候,页面上的某个表单字段包含只读数据,这一数据要在表单上显示,但是不希望用户修改它。可以使用 HTML 属性 readonly 避免用户修改字段,但是并非所有浏览器都支持这个属性。
<!DOCTYPE html>
<html>
<head>
<title>Forbidding an entry</title>
<script src="script07.js"></script>
</head>
<body>
<form action="#">
<h3>
Your message: <textarea rows="5" cols="30">Enter your message here </textarea>
<br><br>
Will be sent to: <input type="text" value="js9@javascriptworld.com" readonly size="25" />
</h3>
</form>
</body>
</html>
window.onload = initForm;
function initForm() {
var allTags = document.forms[0].getElementsByTagName("*");
for (var i=0; i<allTags.length; i++) {
if (allTags[i].readOnly) {
allTags[i].onfocus = function() {
this.blur();
}
}
}
}
8.4 键事件处理
除了鼠标之外,另一种主要的输入设备是键盘。除非以后出现直接用思想控制的计算机设备,否
则计算机还是离不开键盘。与鼠标一样, JavaScript 也为处理键盘提供了一些事件。
8.4.1 onkeydown事件
如果用户能够用键盘和鼠标两种方式控制网页,那么会很方便。通过使用键事件处理程序,可以
在用户按下适当的键时执行相应的操作。
幻灯片的 HTML
<!DOCTYPE html>
<html>
<head>
<title>Image Slideshow</title>
<link rel="stylesheet" href="script08.css">
<script src="script08.js"></script>
</head>
<body>
<h3 class="centered">
<img src="images/callisto.jpg" id="myPicture" alt="Slideshow"><br>
Use the right and left arrows on your keyboard to view the slideshow
</h3>
</body>
</html>
body {
background-color: #FFF;
}
.centered {
text-align: center;
}
img#myPicture {
width: 262px;
height: 262px;
}
document.onkeydown = keyHit;
var thisPic = 0;
function keyHit(evt) {
var myPix = new Array("images/callisto.jpg", "images/europa.jpg","images/io.jpg", "images/
➝ ganymede.jpg");
var imgCt = myPix.length-1;
var ltArrow = 37;
var rtArrow = 39;
if (evt) {
var thisKey = evt.which;
}
else {
var thisKey = window.event.keyCode;
}
if (thisKey == ltArrow) {
chgSlide(-1);
}
else if (thisKey == rtArrow) {
chgSlide(1);
}
function chgSlide(direction) {
thisPic = thisPic + direction;
if (thisPic > imgCt) {
thisPic = 0;
}
if (thisPic < 0) {
thisPic = imgCt;
}
document.getElementById("myPicture").src = myPix[thisPic];
}
}
8.4.2 onkeyup事件
onkeyup 事件处理程序与 onkeydown 处理程序相同,唯一的差异是,它在用户已按下并释放键的过程中触发。
8.4.3 onkeypress事件
当用户按下并释放键时触发 onkeypress 事件。
8.5 高级事件处理
除了本书前面提到的事件处理,还有另外一种事件处理模型,通常称为 DOM Level 2 事件处理程序。这种更为灵活的新方法有不少优点。
有一种通用的方法设置几类事件处理程序。
可为单个事件注册多个事件处理程序,也就是说添加其他事件处理程序不会覆写已有的事件处理程序。
能够控制事件冒泡或者捕获(请查看补充内容“冒泡和捕获”)。
事件可触发其他事件。
事件处理程序很容易被移除。
8.5.1 addEventListener方法
这里的任务跟前一个任务一样,只是这个事件处理程序是通过 addEventListener()设置的
document.addEventListener("keydown",keyHit,false);
var thisPic = 0;
function keyHit(evt) {
var myPix = new Array("images/catseyenebula.jpg", "images/crabnebula.jpg","images/eskimonebula.jpg",
➝ "images/ringnebula.jpg");
var imgCt = myPix.length-1;
var ltArrow = 37;
var rtArrow = 39;
if (evt) {
var thisKey = evt.which;
}
else {
var thisKey = window.event.keyCode;
}
if (thisKey == ltArrow) {
chgSlide(-1);
}
else if (thisKey == rtArrow) {
chgSlide(1);
}
function chgSlide(direction) {
thisPic = thisPic + direction;
if (thisPic > imgCt) {
thisPic = 0;
}
if (thisPic < 0) {
thisPic = imgCt;
}
document.getElementById("myPicture").src = myPix[thisPic];
}
}
addEventListener()函数有 3 个参数:事件本身(目标)、触发事件时调用的函数(监听器),以及用来指定事件被捕获( true)还是冒泡( false)的布尔值。
8.5.2 removeEventListener方法
该方法允许从它的目标事件移除事件监听器。
8.5.3 dispatchEvent方法
该方法允许从代码中的其他位置触发事件处理程序。它接收一个参数: Event 对象。例如,如果要创建、初始化并分派一个事件来点击链接,代码可以这样:
var evt = document.createEvent(“Event”);
evt.initEvent(“click”, true, false);
document.getElementById(“theLink”).dispatchEvent(evt);
8.5.4 initEvent方法
该方法初始化已创建的事件(通常是通过调用 document.createEvent(“Event”);来实现的)。它接收三个参数:事件类型、表示事件是否冒泡的布尔值,以及表示事件能否被取消的布尔值。
8.5.5 stopPropagation方法
该方法阻止触发事件流中的其他事件,它没有参数。
8.5.6 preventDefault方法
该方法取消正在进行的事件(如果该事件是可取消的),它没有参数。
我们可以将网页的结构想象为一棵树。比如说网页的主体可以包含表格,表格本身又包含多行,而表格行内包含了若干单元格,见图 。比方说,你编写了一个脚本,一旦鼠标移过页面上的元素,就会弹出提示框( alert)。如果移过单元格,你希望弹出“移过单元格”的提示,你肯定能收到。不仅如此,随后你还会收到“移过行”、“移过表格”的提示,最后是“移过主体”。这就是事件冒泡,也就是说事件从树的下面向上面冒泡。这是网页工作的一般方式。
但是,如果你想让事件以相反的方向发生呢,也就是从上向下?这种情况就称为事件捕获,脚本弹出提示框的顺序是主体、表格、行,最后是单元格。这是使用高级事件处理程序的一大优势:调用 addEventListener()的时候,开发人员可以控制事件发生的方向。