JavaScript高级程序设计:第八章

1.window对象——BOM的核心

BOM的核心对象时window,它表示浏览器的一个实例。在浏览器中,window对象有双重角色,它既是通过javascript访问浏览器窗口的一个接口,又是ECMAscript规定的global对象。这意味着在网页中定义的任何一个对象、变量和函数,都以window作为其global对象,因此有权访问parseInt()等方法。

(1)全局作用域

由于window对象同时扮演着ECMAScript中global对象的角色,因此所有在全局作用域中声明的变量、函数都会变成window对象的属性和方法。来看下面的例子:

var age = 29 ;

function sayAge(){

alert(this.age);

}

alert(window.age);        //29

sayAge();                //29

window.sayAge();         //29

我们在全局作用域中定义了一个变量age和一个函数sayAge(),它们被自动归在了window对象名下。于是,可以通过window.age访问变量age,可以通过window.sayAge()访问函数sayAge()。由于sayAge()存在于全局作用域中,因此this.age被映射到window.age,最终显示的仍然是正确的。

抛开全局变量会成为window对象的属性不谈,定义全局变量与在window对象上直接定义属性还是有一点差别的:全局变量不能通过delete操作符删除,而直接在window对象上定义的属性可以。例如:

var age = 29;

window.color = “red”;

//在IE < 9时抛出错误,在其他所有浏览器中都返回false

delete window.age;

//在IE < 9时抛出错误,在其他所有浏览器中都返回true

delete window.color ;     //returns true

alert(window.age) ;       //29

alert(window.color) ;      //undefined

刚才使用var语句添加的window属性有一个名为[[Configurable]]的特性,这个特性的值被设置为false,因此这样定义的属性不可以通过delete操作符删除。IE8及更早版本在遇到使用delete删除window属性的语句时,不管该属性最初是如何创建的,都会抛出错误,以示警告。

另外,还要记住一件事:尝试未访问声明的变量会抛出错误,但是通过查询window对象,可以知道某个可能未声明的变量是否存在。例如:

//这里会抛出错误,因为oldValue未定义

var newValue = oldValue ;

//这里不会抛出错误,因为这是一次属性查询

//newValue的值是undefined

var newValue = window.oldValue ;

(2)窗口关系及框架

如果页面中包含框架,则每个框架都有自己的window对象,并且保存在frames集合中。在frames集合中,可以通过数值索引或者框架名称来访问相应的window对象。每个window对象都有一个name属性,其中包含框架的名称。下面是一个包含框架的页面:

<html>

<head>

<title>Frameset Example</title>

</head>

<frameset rows=”160 , * ”>

<frame src=”frame.htm” name=”topFrame”>

<frameset cols=”50%,50%”>

<frame src=”anotherframe.htm” name=”leftFrame”>

<frame src=”yetanotherframe.htm” name=”rightFrame”>

</frameset>

</frameset>

</html>

以上代码创建了一个框架集,其中一个框架居上,两个框架居下。对这个例子而言,可以通过window.frames[0]或者window.frames[“topFrame”]来引用上方的框架。

(3)窗口位置

用来确定和修改window对象位置的属性和方法有很多。IE、Safari、Opera和Chrome都提供了screenLeft和screenTop属性,分别用于表示窗口相对于屏幕左边和上边的位置。Firefox则在screenX和screenY属性中提供相同的窗口位置信息,Safari和Chrome也同时支持这两个属性。Opera虽然也支持screenX和screenY属性,但与screenLeft和screenTop属性并不对应,因此建议大家不要再Opera中使用它们。使用下列代码可以跨浏览器取得窗口左边和上边的位置。

var leftPos = (typeof window.screenLeft==”number”) ?

window.screenLeft : window.screenX ;

var topPos = (typeof window.screenTop==”number”) ?

window.screenTop : window.screenY ;

这个例子运用二元操作符首先确定screenLeft和screenTop属性是否存在,如果是(在IE、Safari、Opera和Chrome中),则取得这两个属性的值。如果不存在,则取得screenX和screenY的值。

使用moveTo()和moveBy()方法倒是有可能将窗口精确地移动到一个新位置。这两个方法都接收两个参数,其中moveTo()接受的是新位置的x和y坐标值,而moveBy()接受的是在水平和垂直方向上移动的像素数。下面来看几个例子:

//将窗口移动到屏幕左上角

window.moveTo(0,0);

//将窗口向下移动100像素

window.moveBy(0,100);

//将窗口向左移动50像素

window.moveBy(-50,0);

需要注意的是,这两个方法可能会被浏览器禁用;而且,在Opera和IE7中默认就是禁用的。

(4)窗口大小

跨浏览器确定一个窗口大小不是一件简单的事。IE9+、Firefox、Safari、Opera和Chrome均为此提供了4个属性:innerWidth、innerHeight、outerWidth和outerHeight。在IE9+、Safari和Firefox中,outerWidth和outerHeight返回浏览器窗口本身的尺寸。在Opera中,这两个属性的值表示页面视图容器的大小。而innerWidth和innerHeight则表示该容器中页面视图区的大小。在chrome中,outerWidth、outerHeight与innerWidth、innerHeight返回相同的值,即视口大小而非浏览器窗口大小。

IE8及更早版本没有提供取得当前浏览器窗口尺寸的属性;不过,它通过DOM提供了页面可见区域的相关信息。

在IE、Firefox、Safari、Opera和Chrome中,document.documentElement.clientWidth和document.documentElement.clientHeight中保存了页面视口的信息。在IE6中,这些属性必须在标准模式下才有效;如果是混杂模式,就必须通过document.body.clientWidth和document.body.clientHeight取得相同信息。而对于混杂模式下的Chrome,则无论通过document.documentElement还是document.body中的clientWidth和clientHeight属性,都可以取得视口的大小。

虽然最终无法确定浏览器窗口本身的大小,但却可以取得页面视口的大小,如下所示

var pageWidth = window.innerWidth , pageHeight = window.innerHeight ;

if(typeof pageWidth != “number”){

if(document.compatMode == “CSS1Compat”){

pageWidth = document.documentElement.clientWidth ;

pageHeight = document.documentElement.clientHeight ;

} else {

pageWidth = document.body.clientWidth ;

pageHeight = document.body.clientHeight ;

}

}

在以上代码中,我们首先将window.innerWidth和window.innerHeight的值分别赋给了pageWidth和pageHeight。然后检查pageWidth中保存的是不是一个数值;如果不是,则通过检查document.compatMode来确定页面是否处于标准模式。如果是,则分别使用document.documentElement.clientWidth和document.documentElement.clientHeight的值。否则,就用document.body.clientWidth和document.body.clientHeight的值。

(5)导航和打开窗口

使用window.open()方法既可以导航到一个特定的URL,也可以打开一个新的浏览器窗口。这个方法可以接受4个参数:要加载的URL、窗口目标、一个特性字符串以及一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值。通常只需传递第一个参数,最后一个参数只在不打开新窗口的情况下使用。

如果为window.open()传递了第二个参数,而且该参数是已有窗口或框架的名称,那么就会在具有该名称的窗口或框架中加载第一个参数指定的URL。看下面的例子:

//等同于< a href=”http://www.wrox.com” target=”topFrame”></a>

window.open(”http://www.wrox.com/” , “topFrame”);

调用这行代码,就如同用户单击了href属性为”http://www.wrox.com/,target”属性为”topFrame”的链接。

①弹出窗口

如果给window.open()传递的第二个参数并不是一个已经存在的窗口或框架,那么该方法就会根据在第三个参数位置上传入的字符串创建一个新窗口或新标签页。如果没有传入第三个参数,那么就会打开一个带有全部默认设置的新浏览器窗口。在不打开窗口的情况下,会忽略第三个参数。第三个参数是一个逗号分隔的设置字符串,表示在新窗口中都显示哪些特性。window.open()方法会返回一个指向新窗口的引用。引用的对象与其他window对象大致相似,但我们可以对其进行更多控制。例如,有些浏览器在默认情况下可能不允许我们针对主浏览器窗口调整大小或移动位置,但却允许我们针对通过window.open()创建的窗口调整大小或移动位置。

调用close()方法可以关闭新打开的窗口。

wroxWin.close();

但是,这个方法仅适用于通过window.open()打开的弹出窗口。对于浏览器的主窗口,如果没有得到用户的允许是不能关闭它的。不过,弹出窗口倒是还可以调用top.close()在不经用户允许的情况下关闭自己。弹出窗口关闭之后,窗口的引用仍然还在,但除了像下面这样检测其closed属性之外,已经没有其他用途了。

wroxWin.close();

alert(wroxWin.closed);     //true

新创建的window对象有一个opener属性,其中保存着打开它的原始窗口对象。这个属性只在弹出窗口中的最外层window对象(top)中有定义,而且指向调用window.open()窗口或框架。例如:

var wroxWin = window.open(“http://www.wrox.com/”,”wroxWindow”,

”height=400,width=400,top=10,left=10,resizable=yes”);

alert(wroxWin.opener==window);    //true

虽然弹出窗口中有一个指针指向打开它的原始窗口,但原始窗口中并没有这样的指针指向弹出窗口。窗口并不跟踪记录它们打开的窗口,因此我们只能在必要的时候自己来手动实现跟踪。

②安全限制

由于广告商在网上使用弹出窗口到达了肆无忌惮的程度,因此浏览器开始对弹出窗口配置方面增加限制。

③弹出窗口屏蔽程序

大多数浏览器都内置有弹出窗口屏蔽程序,而没有内置此类程序的浏览器,也可以安装Yahoo!Toolbar等带有内置屏蔽程序的实用工具。在弹出窗口屏蔽时,就应该考虑两种可能性如果是浏览器内置的屏蔽程序阻止的弹出窗口,那么window.open()很可能会返回null。此时,只要检测这个返回的值就可以确定弹出的窗口是否被屏蔽了,如下面的例子所示:

var wroxWin = window.open(“http://www.wrox.com”,”_blank”);

if(wroxWin == null){

alert(“The popup was blocked!”);

}

如果是浏览器扩展或其他程序阻止的弹出窗口,那么window.open()通常会抛出一个错误。因此,要想正确地检测出弹出窗口是否被屏蔽,必须在检测返回值的同时,将对window.open()的调用封装在一个try-catch块中。如下所示:

var blocked = false ;

try {

var wroxWin = window.open(“http://www.wrox.com”,“_blank”);

if (wroxWin == null){

blocked = true ;

}

} catch (ex){

blocked = true ;

}

if (blocked){

alert(“The popup was blocked!”);

}

在任何情况下,以上代码都可以检测出调用window.open()打开的弹出窗口是不是被屏蔽了。但要注意的是,检测弹出窗口是否被屏蔽只是一方面,它并不会阻止浏览器显示与屏蔽的弹出窗口有关的消息。

(6)间歇调用和超时调用

javascript是单线程语言,但它允许通过设置超时值和间歇时间值来调度代码在特定的时刻执行。前者是在指定的时间过后执行代码,而后者则是每隔指定的时间就要执行一次代码。

超时调用需要使用window对象的setTimeout()方法,它接受两个参数:要执行的代码和以毫秒表示的时间。其中,第一个参数可以是一个包含javascript代码的字符串,也可以是一个函数。例如,下面对setTimeout()的两次调用都会在一秒钟后显示一个警告框。

//不建议传递字符串!

setTimeout(“alert(‘Hello world!’)” , 1000);

alert(“Hello world!”);

} ,1000);

虽然这两种调用方式都没有问题,但由于传递字符串可能导致性能损失,因此不建议以字符串作为第一个参数。

第二个参数是一个表示等待多长时间的毫秒数,但经过该时间后指定的代码不一定会执行。javascript是一个单线程序的解释器,因此一定时间内只能执行一段代码。为了控制要执行的代码,就有一个javascript任务队列。这些任务会按照将它们添加到队列的顺序执行。setTimeout()的第二个参数告诉javascript再过多长时间把当前任务添加到队列中。如果队列是空的,那么添加的代码会立即执行;如果队列不是空的,那么它就要等前面的代码执行完了之后再执行。

调用setTimeout()之后,该方法会返回一个数值ID,表示超时调用。这个超时调用ID是计划执行代码的唯一标识符,可以通过它来取消超时调用。要取消尚未执行的超时调用计划,可以调用clearTimeout()方法并将相应的超时调用ID作为参数传递给它,如下所示:

//设置超时调用

var timeoutId = setTimeout(function(){

alert(“Hello world!”);

},1000);

//注意:把它取消

clearTimeout(timeoutId);

只要是在指定的时间尚未过去之前调用clearTimeout()就可以完全取消超时调用。前面的代码在设置超时调用之后马上又调用了clearTimeout(),结果就跟什么也没有发生一样。

间歇调用与超时调用类似,只不过它会按照指定的时间间隔重复执行代码,直至间歇调用被取消或者页面被卸载。设置间歇调用的方法是setInterval(),它接受的参数与setTimeout()相同;要执行的代码和每次执行前需要等待的毫秒数。下面来看一个例子:

//不建议传递字符串!

setInterval(“alert(‘Hello world!’)” , 10000);

//推荐的调用方式

setInterval (function(){

alert(“Hello world!”);

} , 10000);

调用setInterval()方法同样也会返回一个间歇调用ID,该ID可用于在将来某个时刻取消间歇调用。要取消尚未执行的间歇调用,可以使用clearInterval()方法并传入相应的间歇调用ID。取消间歇调用的重要性要远远高于取消超时调用,因为在不加干涉的情况下,间歇调用将会一直执行到页面卸载。以下是一个常见的使用间歇调用的例子。

var num = 0 ;

var max = 10 ;

var intervalId = null ;

function incrementNumber() {

num++ ;

// 如果执行次数达到了max设定的值,则取消后续尚未执行的调用

if ( num == max )  {

clearInterval(intervalId) ;

alter(“Done”);

}

}

intervalId = setInterval(incrementNumber , 500);

在这个例子中,变量num每半秒钟递增一次,当递增到最大值时就会取消先前设定的间歇调用。这个模式也可以用超时调用来实现,如下所示:

var num = 0 ;

var max = 10 ;

function incrementNumber() {

num++ ;

//如果执行次数未达到max设定的值,则设置另一次超时调用

if (num < max){

setTimeout(incrementNumber ,500);

} else {

alert(“Done”);

}

}

setTimeout(incrementNumber,500);

(7)系统对话框

浏览器通过alert()、confirm()和prompt()方法可以调用系统对话框向用户显示消息。

①调用alert()方法的结果就是向用户显示一个系统对话框,其中包含指定的文本和一个OK按钮。通常使用alert()生成的“警告”对话框向用户显示一些他们无法控制的消息,例如错误消息。而用户只能在看完消息后关闭对话框。

②confirm()方法生成的对话框可以包含两种选项:OK或者cancel。通过检查confirm()方法返回的布尔值来却定用户的选择:true表示单击了OK,false表示单击了Cancel或右上角的X按钮。

③prompt()方法生成的对话框是一个提示框。用户提示用户输入一些文本。提示框中除了显示OK和Cancel按钮之外还会显示一个文本输入域,以提供用户在其中输入内容。prompt()方法接受两个参数:要显示给用户的文本提示和文本输入域的默认值。

④还有两种可以调用javascript对话框的方法:find()和print()。

//显示“打印”对话框

window.print();

//显示“查找”对话框

window.find();

二、location对象

location是最有用的BOM对象之一,它提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功能。事实上,location对象是很特别的一个对象,因为它既是window对象的属性又是document对象的属性。

(1)位置操作:

使用location对象可以通过很多方式来改变浏览器的位置。例如:使用assign()方法并为其传递一个URL,如下所示:

location . assign(“http://www.wrox.com”);

这样就可以立即打开新URL并在浏览器的历史记录中生成一条记录。如果是将location.href或window.location设置为一个URL值,也会以该值调用assign()方法。例如,下列两行代码与显示调用assign()方法的效果完全一样。

window.location = http://”www.wrox.com”;

location.href = “http://www.wrox.com”;

在这些方法中,最常用的是设置location.href属性。

三、navigator对象

navigator对象现在已经成为识别客户端浏览器的事实标准。

①检测浏览器中是否安装了特定的插件是一种最常见的检测例程。对于非IE浏览器,可以使用plugins数组来达到这个目的。该数组中的每一项都包含下列属性。

name:插件的名字

description:插件的描述

filename:插件的文件名

length:插件所处理的MIME类型数量

一般来说,name属性中会包含检测插件必须的所有信息,但有时候也不完全如此。在检测插件时,需要像下面这样循环迭代每个插件并将插件的name与给定的名字进行比较。

②注册处理程序

Firefox 2为navigator对象新增了registerContentHandler()和registerProtocolHandler()方法。这两个方法可以让一个站点指明它可以处理特定类型的信息。其中,registerContentHandler()方法接收三个参数:要处理的MIME类型、可以处理该MIME类型的页面的URL以及应用程序的名称。例如:

navigator . registerContentHandler(“application/rss+xml”,

“http://www.somereader.com?feed=%s”,“Some Reader”);

四、screen对象

screen对象基本上只用来表民客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素宽度和高度等。

五、history对象

history对象保存着用户上网的历史记录,从窗口被打开的那一刻算起。因为history是window对象的属性,因此每个浏览器窗口、每个标签页乃至每个框架,都有自己的history对象与特定的window对象关联。使用go()方法可以在用户的历史记录中任意跳转。可以向后也可以向前。这个方法接受一个参数表示向后或向前跳转的页面数的一个整数值。来看下面的例子:

//后退一页

history.go(-1);

//前进一页

history.go(1);

//前进两页

history.go(2);

也可以给go()方法传递一个字符串参数,此时浏览器会跳转到历史记录中包含该字符串的第一个位置——可能后退,也可能前进,具体要看那个位置最近。如果历史记录中不包含字符串,那么这个方法什么也不做。

另外,还可以使用两个简写的方法back()和forward()来代替go()。顾名思义,这两个方法可以模仿浏览器的“后退”和“前进”按钮。

上一篇:css布局(转载)


下一篇:【转】深入理解Java:SimpleDateFormat安全的时间格式化