Javascript学习指南(第2版)笔记(三) 排错、调试、事件捕获


1、排错、调试
2、事件
3、Event对象
4、事件冒泡
5、事件句柄和 this
6、DOM Level 2事件模型
7、测验





1、排错、调试


     Firebug是最常用的 Firefox开发工具,同时常用的 Web工具还有 Web Developer toolkit,该工具功能包括页面 HTML和 CSS代码的校验、可访问性检查、查看 CSS和 cookies、检查图像、查看 JavaScript修改后的页面源代码(包括动态源代码)。




2、事件

     事件包括:用户界面事件(鼠标、键盘触发的)、逻辑事件(一个处理的结果)、和变化事件(修改文档的操作)。

事件句柄 (Event Handlers)

HTML 4.0 的新特性之一是能够使 HTML 事件触发浏览器中的行为,比如当用户点击某个 HTML 元素时启动一段 JavaScript。下面是一个属性列表,可将之插入 HTML 标签以定义事件的行为。

属性 此事件发生在何时... IE F O W3C
onabort 图像的加载被中断。 4 1 9 Yes
onblur 元素失去焦点。 3 1 9 Yes
onchange 域的内容被改变。 3 1 9 Yes
onclick 当用户点击某个对象时调用的事件句柄。 3 1 9 Yes
ondblclick 当用户双击某个对象时调用的事件句柄。 4 1 9 Yes
onerror 在加载文档或图像时发生错误。 4 1 9 Yes
onfocus 元素获得焦点。 3 1 9 Yes
onkeydown 某个键盘按键被按下。 3 1 No Yes
onkeypress 某个键盘按键被按下并松开。 3 1 9 Yes
onkeyup 某个键盘按键被松开。 3 1 9 Yes
onload 一张页面或一幅图像完成加载。 3 1 9 Yes
onmousedown 鼠标按钮被按下。 4 1 9 Yes
onmousemove 鼠标被移动。 3 1 9 Yes
onmouseout 鼠标从某元素移开。 4 1 9 Yes
onmouseover 鼠标移到某元素之上。 3 1 9 Yes
onmouseup 鼠标按键被松开。 4 1 9 Yes
onreset 重置按钮被点击。 4 1 9 Yes
onresize 窗口或框架被重新调整大小。 4 1 9 Yes
onselect 文本被选中。 3 1 9 Yes
onsubmit 确认按钮被点击。 3 1 9 Yes
onunload 用户退出页面。 3 1 9 Yes

注:HTML DOM Event 对象 http://www.w3school.com.cn/htmldom/dom_obj_event.asp


内联模式/内联注册模式
以属性的形式为 HTML元素添加属性的方法。
<body onload="var 1=23; i*=3; alert(i);">
<body onload="calcNumber();">

传统模式/传统注册模式
通过对象属性将一个函数指派为事件句柄。如果想禁用事件处理,那么可以将事件句柄的值赋为 null。
window.onload = calcNumber;


注:
     在 DOM Level 0事件模型中,任何对象只允许指定一个事件句柄。如果你想针对某一特定对象的某个事件指定多个函数,则需要在事件句柄代码中列出他们:

内嵌模式:
<body onload="helloMsg(); helloTwice();">

传统模式:
function helloMsg() {
    var helloString = "hello there";
    alert(helloString);
    helloTwice();
}

当要求浏览器停止执行事件行为,可以从事件句柄函数中返回 false值。




3、Event对象

     Event对象是和所有事件相关的。它有一些用来提供事件相关信息的属性,如 Web页面中鼠标点击的位置。

     IE将 Event视为 window对象的属性。当处理事件时,将通过程序访问 window对象,其所包含的数据也会相应的进行填充。

function mouseDown() {
    
var locString = "X = " + window.event.screenX + " Y = " + window.event.screenY;
    alert(locString);
}

document.onmousedown = mouseDown;


     在基于 Netscape的浏览器(如 Firefox、Mozilla、Opera和 Safari)中,获取 Event对象的方法是不同的:他将作为函数的一部分传入。

function mouseDown(theEvent) {
    
var locString = "X = " + theEvent.screenX + " Y = " + theEvent.screenY;
    alert(locString);
}

document.onmousedown 
= mouseDown;


     处理这些浏览器差异的方法之一是检查传入函数的 Event对象是否已经实例化。如果是,那么将这个 Event对象赋给一个局部变量;否则,将假定 window.event为该事件,并将其赋给这个局部变量。

function mouseDown(nsEvent) {
    
var theEvent = nsEvent ? nsEvent : window.event;    //判断 nsEvent对象是否已定义。定义则赋值,否则选择 window.event属性
    var locString = "X = " + theEvent.screenX + " Y = " + theEvent.screenY;
    alert(locString);
}

document.onmousedown 
= mouseDown;



鼠标 / 键盘属性

属性 描述 IE F O W3C
altKey 返回当事件被触发时,"ALT" 是否被按下。 6 1 9 Yes
button 返回当事件被触发时,哪个鼠标按钮被点击。 6 1 9 Yes
clientX 返回当事件被触发时,鼠标指针的水平坐标。 6 1 9 Yes
clientY 返回当事件被触发时,鼠标指针的垂直坐标。 6 1 9 Yes
ctrlKey 返回当事件被触发时,"CTRL" 键是否被按下。 6 1 9 Yes
metaKey 返回当事件被触发时,"meta" 键是否被按下。 No 1 9 Yes
relatedTarget 返回与事件的目标节点相关的节点。 No 1 9 Yes
screenX 返回当某个事件被触发时,鼠标指针的水平坐标。 6 1 9 Yes
screenY 返回当某个事件被触发时,鼠标指针的垂直坐标。 6 1 9 Yes
shiftKey 返回当事件被触发时,"SHIFT" 键是否被按下。 6 1 9 Yes

注:HTML DOM Event 对象 http://www.w3school.com.cn/htmldom/dom_obj_event.asp

注:
     在 IE中,fromElement 对于 mouseover 和 mouseout 事件,fromElement 引用移出鼠标的元素。 
     而在 Mozilla/Firefox中,relatedTarget 返回与事件的目标节点相关的节点。
要解决浏览器差异,可以使用:
var oldElement = theEvent.fromElement ? theEvent.fromElement : theEvent.relatedTarget;




4、事件冒泡

     如果你为多个嵌套的元素设置相同的事件句柄,会发生什么呢?他们将以什么样的顺序触发?如果你想使得一次只影响一个元素,那么如何保存触发事件句柄的事件呢?

     要管理元素堆栈中的事件,其中一个方法就是众所周知的事件冒泡。在事件冒泡中,最内部的元素将首先触发该事件,然后堆栈内的下一个元素触发该事件,以此类推,直到最外面的元素。如果事件句柄被指定给所有元素,那么这些事件将依次被触发。

     如果 div2在 div1内部,而 div1又在 document内部,三者都做了事件处理。当事件触发的时候,优先最里面的 div2元素,然后是 div1元素,最后是 document元素。

     如果你有一个元素堆栈,并且只希望一个元素触发该事件句柄,那么你可以取消事件冒泡机制。如果在 IE中要取消一个事件冒泡,可以使用 IE中事件的 cancelBubble属性;对于 Mozilla而言,则应该使用事件的 stopPropagation方法。你可以先检查 stopPropagation方法是否存在,然后根据其结果确定使用哪种方法:

function stopEvent(evnt) {
    
if (evnt.stopPropagation) evnt.stopPropagation;
    
else evnt.cancelBubble = true;
}
//注:IE 7中调试出错,提示信息 "stopPropagation为空或不是对象"。



5、事件句柄和 this

     this关键字表示的是当前调用的函数或者方法的所有者。对于一个全局变量而言,它表示的就是 window对象。对于一个对象的方法而言,它表示的就是该对象实例。而在一个事件句柄中,它表示的就是接收到该事件的元素。

document.getElementById("first").onmousedown = function() {
    alert(
this);    //在 Firefox中将输出 "[object HTMLDivElement]"
    alert("first element event");
}



6、DOM Level 2事件模型


     对于堆栈内元素的事件处理,还有一种被称为事件捕捉(event capturing)或 cascade-down的事件处理机制。对于前面这个包含3个元素的示例而言,事件将从最外面的元素开始触发:window -> div1 -> div2。

     老事件模型和新的 DOM Level 2事件模型之间,主要区别:
a.新事件模型并不依赖于特定的事件来处理属性;
b.你可以对任何一个对象的任何一种事件注册多个事件句柄函数。

     新的事件句柄提供的3个方法:
addEventListener,添加一个事件监听器;
removeEventListener,删除一个事件监听器;
dispatchEvent,分发一个新的事件。

示例:
object.addEventListener('event', eventFunction, boolean);

     如 click或 load之类的事件是其第一参数;第二个参数是指定的事件句柄函数;第三个参数用来指定事件是以 cascade-down或者冒泡模式处理的。当第三个参数为 false时这个事件监听器将以冒泡模式处理,否则将把这个事件监听器改成事件捕捉模型。

function cascadeDown(evnt) {
    alert(
"Capturing: " + this);
}

function bubbleUp(evnt) {
    alert(
"Bubbling: " + this);
}

window.onload 
= setup;

function setup(evnt) {
    
//事件捕捉
    document.addEventListener("click", cascadeDown, true);
    document.forms[
0].addEventListener("click", cascadeDown, true);
    document.forms[
0].elements[0].addEventListener("click", cascadeDown, true);
    
    
//事件冒泡
    document.addEventListener("click", bubbleUp, false);
    document.forms[
0].addEventListener("click", bubbleUp, false);
    document.forms[
0].elements[0].addEventListener("click", bubbleUp, false);
}

/*
在 Firefox中,单击按钮将顺序生成6个对话框

Capturing: [object HTMLDocument]
Capturing: [object HTMLFormElement]
Capturing: [object HTMLInputElement]
Bubbling: [object HTMLInputElement]
Bubbling: [object HTMLFormElement]
Bubbling: [object HTMLDocument]

*/



     如果你想停止事件执行时,可以在函数中调用 stopPropagation方法:
function cascadeDown(evnt) {
    ...
    evnt.stopPropagation();
}


     如果要彻底删除一个事件监听器,可以使用 removeEventListener方法:
document.removeEventListener("click", cascadeDown, true);


     在 IE中,与 addEventListener和 removeEventListener方法相似的是 attachEvent和 detachEvent,对应语法是:
object.attachEvent("eventhandler", function);
第一个参数是事件句柄,第二个是其函数。detachEvent语法类似。


跨浏览器解决方案:

window.onload = setup;
window.onunload 
= cleanup;

function setup(evnt) {
    
var evtObject = document.getElementById("clickme");
    
    
//检查对象模型
    if (evtObject.addEventListener) evtObject.addEventListener("click", clickMe, false);
    
else if (evtObject.attachEvent) evtObject.attachEvent("onclick", clickMe);
    
else if (evtObject.onclick) evtObject.onclick=clickMe;    
}

/*清理
在 IE中,需要跟踪 window的 unload事件,然后调用 detachEvent方法清理,释放相应的内存
而 addEventListener方法使用的内存是无需清理的。
*/
function cleanup() {
    
var evtObject = document.getElementById("clickme");
    
if (evtObject.detachEvent) evtObject.detachEvent("onclick", clickMe);
}

function clickMe() {
    alert(
"clickMe");
}



IE 属性

除了上面的鼠标/事件属性,IE 浏览器还支持下面的属性:

属性 描述
cancelBubble 如果事件句柄想阻止事件传播到包容对象,必须把该属性设为 true。
fromElement 对于 mouseover 和 mouseout 事件,fromElement 引用移出鼠标的元素。
keyCode 对于 keypress 事件,该属性声明了被敲击的键生成的 Unicode 字符码。对于 keydown 和 keyup 事件,它指定了被敲击的键的虚拟键盘码。虚拟键盘码可能和使用的键盘的布局相关。
offsetX,offsetY 发生事件的地点在事件源元素的坐标系统中的 x 坐标和 y 坐标。
returnValue 如果设置了该属性,它的值比事件句柄的返回值优先级高。把这个属性设置为 fasle,可以取消发生事件的源元素的默认动作。
srcElement 对于生成事件的 Window 对象、Document 对象或 Element 对象的引用。
toElement 对于 mouseover 和 mouseout 事件,该属性引用移入鼠标的元素。
x,y 事件发生的位置的 x 坐标和 y 坐标,它们相对于用CSS动态定位的最内层包容元素。

注:HTML DOM Event 对象 http://www.w3school.com.cn/htmldom/dom_obj_event.asp


标准 Event 属性

下面列出了 2 级 DOM 事件标准定义的属性。

属性 描述 IE F O W3C
bubbles 返回布尔值,指示事件是否是起泡事件类型。 No 1 9 Yes
cancelable 返回布尔值,指示事件是否可拥可取消的默认动作。 No 1 9 Yes
currentTarget 返回其事件监听器触发该事件的元素。 No 1 9 Yes
eventPhase 返回事件传播的当前阶段。       Yes
target 返回触发此事件的元素(事件的目标节点)。 No 1 9 Yes
timeStamp 返回事件生成的日期和时间。 No 1 9 Yes
type 返回当前 Event 对象表示的事件的名称。 6 1 9 Yes

注:HTML DOM Event 对象 http://www.w3school.com.cn/htmldom/dom_obj_event.asp




7、测验

Q1:使用 DOM Level 0方法为 document的 click事件指定一个事件句柄函数。
A1:document.onclick = clickMe;


Q2:使用 DOM Level 2事件处理机制为 document添加 click事件句柄。
A2:document.addEventListener("click", clickMe, false);


Q3:如果使事件处理机制能安全运行所有浏览器?
A3:
    if (evtObject.addEventListener) evtObject.addEventListener("click", clickMe, false);
    else if (evtObject.attachEvent) evtObject.attachEvent("onclick", clickMe);
    else if (evtObject.onclick) evtObject.onclick=clickMe;   


Q4:对于为 document对象指定的 onclick事件句柄,如何知道是在屏幕的什么位置执行了单击操作?
A4:
     如果使用 DOM Level 0事件处理系统,那么将无法使用 window对象的 event对象,也不能将其作为参数传给函数。
     对于 DOM Level 2事件处理模型而言,event对象将会传给事件句柄函数,你可以通过 event对象访问其 screenX和 screenY属性。


Q5:使用 DOM Level 2事件系统,如何阻止从其他元素中冒泡上来的事件。
A5:
     IE所支持的方法和绝大多数浏览器所支持的方法有所不同,因此你需要分别支持 IE和其他浏览器。你可以检查 event对象是否支持 stopPropagation方法。如果支持,则调用它;否则就将 cancelBubble属性的值设置为 true。


Q7:捕获 document对象的 keydown事件
A7:

window.onload = function() {    
    
if (document.addEventListener) document.addEventListener("keydown", getKey, false);
    
else if (document.attachEvent) document.attachEvent("onkeydown", getKey);
    
else if (document.onkeydown) document.onkeydown=getKey;    
}

function getKey(evnt) {
    
var theEvent = evnt ? evnt : window.event;
    alert(theEvent.which);  
//Firefox 返回值,IE 7提示 undefined
}
posted on 2010-05-29 09:25  黄小二  阅读(694)  评论(0编辑  收藏  举报