JS高级程序设计笔记(七)BOM

目录

window对象

窗口关系及框架

窗口位置

窗口大小

导航和打开窗口

间歇性调用和超时调用

系统对话框

location对象

查询字符串参数

位置操作

检测插件

注册处理程序

screen对象

history对象


window对象

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

由于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,最终显示的仍然是正确的结果。

全局变量不能够通过delete操作符删除,而直接在window对象上的定义的属性可以。

var age = 29;
window.color = "red";
//在IE<9时抛出错误,在其他所有浏览器中都返回false
delete window.age;

//在IE<9时抛出错误,在其他所有浏览器中都返回true
delete window.color; //return true

alert(window.age);//29
alert(window.color);//undefined

使用var语句添加的window属性有一个名为[[Configurable]]的特性,这个特性的值被设置为false,因此这样定义的属性不可以通过delete操作符删除。

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

//这里会抛出错误,因为oldValue未定义
var newValue = oldValue;
//这里不会抛出作为,因为这是一个属性查询
//newValue的值是undefined
var newValue = window.oldValue;

窗口关系及框架

如果页面中包含框架,则每个框架都拥有自己的window对象,并且保存在frames集合中。在frames集合中,可以通过数值索引(从0开始,从左至右,从上到下)或者框架名称来访问相应的window对象。每个window对象都有一个name属性,其中包含框架的名称。

<html>
<head>
	<title>Frameset Example</title>
</head>
<frameset rows = "160,*">
	<frame src = "frame.html" name = "topFrame">
		<frameset cols = "50%,50%">
			<frame src="anotherframe.html" name = "leftFrame"></frame>
			<frame src="yetanotherframe.html" name = "rightFrame"></frame>
		</frameset>
	</frame>
</frameset>
</html>

以上代码创建了一个框架集,其中一个框架居上,两个框架居下。对这个例子而言,可以通过window.frames[0]或者window.frames["topFrame"]来引用上方的框架。不过,恐怕你最好使用top而非window来引用这些框架。

我们知道,top对象始终指向最高层的框架,也就是浏览器窗口。使用它可以确保在一个框架中正确地访问另一个框架。因为对于在一个框架中编写的任何代码来说,其中的window对象指向的都是那个框架的特定实例,而非最高层的框架。

与top相对的另一个window对象是parent。顾名思义,parent对象始终指向当前框架的直接上层框架。在某些情况下,parent有可能等于top;但在没有框架的情况下,parent一定等于top(此时它们都等于window)。

<html>
<head>
	<title>Frameset Example</title>
</head>
<frameset rows = "160,*">
	<frame src = "frame.html" name = "topFrame">
		<frameset cols = "50%,50%">
			<frame src="anotherframe.html" name = "leftFrame"></frame>
			<frame src="anotherframeset.html" name = "rightFrame"></frame>
		</frameset>
	</frame>
</frameset>
</html>

这个框架集中的一个框架包含了另一个框架集,该框架集的代码如下

<html>
<head>
	<title>Frameset Example</title>
</head>
<frameset cols = "50%,50%">
	<frame src="red.html" name = "redFrame"></frame>
	<frame src="blue.html" name = "blueFrame"></frame>
</frameset>
</html>

浏览器在加载完第一个框架集以后,会继续将第二个框架集加载到rightFrame中。如果代码位于redFrame中,那么parent对象指的就是rightFrame。可是,如果代码位于topFrame中。则parent指向的是top,因为topFrame的直接上层框架就是最外层框架。

注意,除非最高层窗口是通过window.open()打开的,否则其window对象的name属性不会包含任何值。

与框架头冠的最后一个对象时self,它始终指向window;实际上,self和window对象可以互换使用。引入self对象的目的只是为了与top和parent对象对应起来,因此它不格外包含其他值。

所有这些对象都是window对象的属性,可以通过window.parent、window.top等形式来访问。同时,这也意味着可以将不同层次的window对象连缀起来,window.parent.parent.frames[0].

窗口位置

用来确定和修改window对象位置的属性和方法有很多。IE、Safari、Opera和Chrome都提供了screenLeft和screenTop属性,分别用于表示窗口相对于屏幕左边和上边的位置。Firefox则在screenX和screenY属性中提供相同的窗口位置信息,Sarari和Chrome也同时支持这两个属性。

使用下列代码可以跨浏览器取得窗口左边和上边的位置。

var leftPos = (typeof window.screenLeft == "number")? window.screenLeft : window.screenX;
var topPos = (typeof window.screenTop == "number")? window.screenTop : window.screenY;

无法在跨浏览器的条件下取得窗口左边和上边的精确坐标值。然而,使用moveTo()和moveBy()方法倒是有可能将窗口精确地移动到一个新位置。这两个方法都接收两个参数,其中moveTo()接收的是新位置的x和y坐标值,而moveBy()接收的是水平和垂直方向上移动的像素数。

//将窗口移动到屏幕左上角
window.moveTo(0,0);
//将窗口向下移动100像素
window.moveBy(0,100);
//将窗口移动到(200,300)
window.moveTo(200,300);
//将窗口向左移动50像素
window.moveBy(-50,0);

这两个方法可能会被浏览器禁用,而且都不适用与框架,只能对最外层的window对象使用。

窗口大小

跨浏览器确定一个窗口的大小不是一件简单的事。虽然最终无法确定浏览器窗口本身的大小,但却可以取得页面视口的大小,如下所示。

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.body.clientHeight的值。

对于移动设备,window.innerWidth和window.innerHeight保存着可见视口,也就是屏幕上可见页面区域的大小。移动IE浏览器不支持这些属性,但通过document.documentElement.clientWidth 和document.documentElement.clientHeight提供了相同的信息。随着页面缩放,这些值也会相应变化。

在其他移动浏览器中,document.documentElement度量的是布局视口,即渲染后页面的实际大小。移动IE浏览器把布局视口的信息保存在document.body.clientWidth和documnet.body.clientHeight中。这些值不会随着页面缩放变化。

另外,使用resizeTo()和resizeBy()方法可以调整浏览器窗口的大小。这两个方法都接收两个参数,其中resizeTo()接收浏览器窗口的新宽度和新高度,而resizeBy()接收新窗口与原窗口的宽度和高度之差。

//调整到100*100
window.resizeTo(100,100);
//调整到200*150
window.resizeBy(100,50);
//调整到300*300
window.resizeTo(300,300);

这两个方法与移动窗口位置的方法类似,也可能被浏览器禁用;而且,同样不适用与框架,而只能对最外层的window对象使用。

导航和打开窗口

使用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"的链接。如果有一个名为"topFrame"的窗口或者框架,就会在该窗口或者框架加载这个URL;否则就会创建一个新窗口并将其命名为"topFrame"。此外,第二个参数也可以是下列任何一个特殊的窗口名称:_self、_parent、_top、或_blank.

弹出窗口

如果给window.open()传递的第二个参数并不是一个已经存在的窗口或框架,那么该方法就会根据在第三个参数位置上传入的字符串创建一个新窗口或新标签页。如果没有传入第三个参数,那么就会打开一个带有全部默认设置(工具栏、地址栏和状态栏等)的新浏览器窗口(或者打开一个新标签页——根据浏览器设置)。在不打开新窗口的情况下,会忽略第三个参数。

第三个参数是一个逗号分隔的设置字符串,表示在新窗口中都显示哪些特性。下表列出了可以出现在这个字符串中的设置选项。

 表中所列的部分或全部设置选项,都可以通过逗号分隔的名值对列表来指定。其中名值对以等号表示(注意,整个特性字符串中不允许出现空格),如下面的例子所示。

window.open("http://www.wrox.com/","wroxWindow", "height=400,width=400,top=10,left=10,resizable=yes"); 

这行代码会打开一个新的可以调整大小的窗口,窗口初始大小为400*400像素,并且距屏幕上沿和左边各10像素。

window.open()方法会返回一个新窗口的引用。引用的对象与其他window对象大致相似,但我们可以对其进行更多控制。例如,有些浏览器在默认情况下可能不允许我们针对主浏览器窗口调整大小或者移动位置,但允许我们针对通过window.open()创建的窗口调整大小或移动位置。通过这个返回的对象,可以像操作其他窗口一样操作打开新的窗口。

var wroxWin = window.open("http://www.wrox.com/","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");
//调整大小
wroxWin.resizeTo(500,500);
//移动位置
wroxWin.moveTo(100,100);

使用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

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

有些浏览器会在独立的进程中运行每个标签页。当一个标签页打开另一个标签页时,如果两个window对象之间需要彼此通信,那么新标签页就不能运行在独立的进程中。在Chrome中,将新创建的标签页的opener属性设置为null,即表示在单独的进程中运行新标签页。

var wroxWin = window.open("http://www.wrox.com/","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");
wroxWin.opener = null;

将opener属性设置为null就是告诉浏览器新创建的标签页不需要与打开他的标签页通信,因此可以再独立的进程中进行。标签页之间的联系一旦切断,将没有办法恢复。

弹出窗口屏蔽程序

大多数浏览器都内置有弹出窗口屏蔽程序,而没有内置此类程序的浏览器,也可以安装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()打开的弹出窗口是不是被屏蔽了。但要注意的是,检测弹出窗口是否被屏蔽只是一方面,它并不会阻止浏览器显示与被屏蔽的弹出窗口有关消息。

间歇性调用和超时调用

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

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

//不建议传递字符串
setTimeout("alert('Hello world')",1000);
//推荐调用方式
setTimeout(function(){
	alert("Hello world");
},1000);

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

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

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

//设置超时调用
var timeoutId = setTimeout(function(){
	alert("Hello world!");
},1000);
//注意:把它取消
clearTimeout(timeoutId);

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

超时调用的代码都是在全局作用域中执行的,因此函数中this的值在非严格模式下执行window对象,在严格模式下是undefined。

间歇调用与超时调用类似,只不过它会按照指定的时间间隔重复执行代码,直至间歇调用被取消或者被页面卸载。设置间歇调用的方法是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);
		alert("Done");
	}
}
intervalId = setInterval(incrementNumber,500);

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

var num = 0;
var max = 10;
var intervalId = null;
function incrementNumber(){
	num++;
	//如果执行次数达到了max设定的值,则取消后尚未执行的调用
	if (num < max) {
		setTimeout(incrementNumber,500);
	}
	else{
		alert("Done");
	}
}
setTimeout(incrementNumber,500);

使用超时调用时,没有必要跟踪超时调用ID,因为每次执行代码之后,如果不再设置另一次超时调用,调用就会自动停止。一般认为,使用超时调用来模拟间歇调用的是一种最佳模式。在开发环境下,很少使用真正的间歇调用,原因是后一个间歇调用可能会在前一个间歇调用结束之前启动。而像前面示例中那样使用超时调用,则完全可以避免这一点。所以,最好不要使用间歇调用。

系统对话框

浏览器通过alert()、confirm()和prompt()方法可以调用系统对话框向用户显示消息。系统对话框与浏览器中显示的网页没有关系,也不包含HTML。它们的外观由操作系统及浏览器设置决定。而不是由css决定。此外,通过这几个方法打开的对话框都是同步和模态的。也就是说,显示这些对话框的时候代码会停止执行。而关掉这些对话框后代码又会恢复执行。

alert()向用户显示一个系统对话框,其中包含指定的文本和一个OK按钮。使用alert()生成的警告对话框向用户显示一些他们无法控制的消息,用户只能看完消息后关闭对话框。

confirm()会有确定和取消按钮。为了确定用户是单机了OK还是Cancel,可以检查confirm()方法返回的布尔值:true表示单击了OK,false表示单击了Cancel或单击了x按钮。

if(confirm("Are you sure?")){
	alert("I'm so glad you're sure!");
}else
{
	alert("I'm sorry to hear you're not sure.");
}

这个例子中,第一行代码会向用户显示一个确认对话框。如果用户单击了OK,则通过一个警告框向用户显示消息I'm so glad you're sure!。如果用户单击的是Cancel按钮,则通过警告框显示I'm sorry to hear you're not sure.这种模式经常在用户想要执行删除操作的时候使用,例如删除电子邮件。

最后一种对话框是通过prompt()方法生成的,这是一个“提示”框,用于提示用户输入一些文本。提示框中除了显示OK和Cancel按钮之外,还会显示一个文本输入域,以供用户在其中输入内容。prompt()方法接受两个参数:要显示给用户的文本提示和文本输入域的默认值(可以是一个空字符串)。

调用prompt("What's your name?", "Micheal")

如果点击可ok,则prompt()返回文本输入域的值;如果用户单击了Cancel或没有单击OK而是通过其他方式关闭了对话框,则该方法返回null。

var result = prompt("What is your name ?","");
if(result!==null)
{
	alert("Welcom," + result);
}

除了上面三种对话框之外,Google Chrome浏览器还引入了一种新特性。如果当前脚本在执行过程中会打开两个或多个对话框,那么从第二个对话框开始,每个对话框中都会显示一个复选框,以便用户阻止后续的对话框的显示,除非用户刷新页面。

如果勾选了其中的复选框,并且关闭了对话框,那么除非用户刷新页面,所有后续的系统对话框(包括警告框、确认框和提示框)都会被屏蔽。

还有两个可以通过js打开的对话框,即查找和打印。两个对话框都是异步显示的,能够将控制权立即交还给脚本。这两个对话框与用户通过浏览器菜单的“查找”和“打印”命令打开的对话框相同。而在JS中则可以像下面这样通过window对象的find()和print()方法打开它们。

//显示打印的对话框
window.print();
//显示查找的对话框
window.find();

这两个方法同样不会就用户在对话框中的操作给出任何信息,因此它们的用处有限。另外,既然这两个对话框是异步显示的,那么Chrome的对话框计数器就不会将他们计算在内,所以它们也不会受用户后续对话框显示的影响。

location对象

location提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功能。实际上,location对象时很特别的一个对象,因为它既是window对象的属性,也是document对象的属性;换句话说,window.location和document.location引用的是同一个对象。

location对象的用处不只表现在它保存着当前文档的信息,还表现在它将URL解析为独立的片段,让开发人员可以通过不同的属性访问这些片段。

查询字符串参数

虽然通过上面的属性可以访问到location对象的大多数信息,但其中访问URL包含的查询字符串的属性并不方便。尽管location.search返回从问好到URL末尾的所有内容,但却没有办法逐个访问其中的每个查询字符串参数。为此,可以像线面这样创建一个函数,用以解析查询字符串,然后返回包含所有参数的一个对象。

function getQueryStringArgs(){
	//取得查询字符串并去掉开头的问好
	var qs = (location.search.length > 0 ? location.search.substring(1) : ""),
	//保存数据对象
	args = {},
	//取得每一项
	items = qs.length ? qs.split("&") : [],
	item = null,
	name = null,
	value = null,
	//在for循环中使用
	i = 0,
	len = items.length;
	//逐个将每一项添加到args对象中
	for(i = 0;i < len ; i++)
	{
		item = items[i].split("=");
		name = decodeURIComponent(item[0]);
		value = decodeURIComponent(item[1]);
		if(name.length){
			args[name] = value;
		}
	}
	return args;
}

这个函数的第一步是先去掉查询字符串开头的问好。当然,前提是location.search中必须要包含一或多个字符。然后,所有参数将被保存在args对象中,该对象以字面常量创建。接下来,根据和号(&)来分割每一项,从而返回第一项为参数名,第二项为参数的数组。再使用decodeURIComponent()分别解码name和value(因为查询字符串应该是被编码过)。最后,将name作为args对象的属性,将value作为相应属性的值。下面给出了使用这个函数的示例。

//假设查询字符串是?q = javascript&num = 10
var args = getQueryStringArgs();

alert(args["q"]);  //"javascript"
alert(args["num"]); //"10"

可见,每个查询字符串参数都成了返回对象的属性。这样就极大地方便了对每个参数的访问。

位置操作

使用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属性。

另外,修改location对象的其他属性也可以改变当前加载页面。下面的例子展示了通过将hash、search、hostname、pathname和port属性设置为新值来改变URL。

//假设初始URL为http://www.wrox.com/WileyCDA/
//将URL修改为"http://www.wrox.com/WileyCDA/#section1"
location.hash = '#section1';
//将URL修改为"http://www.wrox.com/WileyCDA/?q=javascript"
location.search = "?q=javascript";

//将URL修改为"http://www.yahoo.com/WileyCDA/"
location.hostname = "www.yahoo.com";
//将URL修改为"http://www.yahoo.com/mydir/"
location.pathname = "mydir";

//将URL修改为"http://www.yahoo.com:8080/WileyCDA/"
location.port = 8080;

每次修改location的属性(hash除外),页面都会以新URL重新加载。

当通过上述任何一种方式修改URL之后,浏览器的历史记录中就会生成一条新记录,因此用户通过点击"后退"按钮都会导航到前面一个页面。要禁止这种行为,可以使用replace()方法。这个方法只接受一个参数,即要导航到的URL;结果虽然会导致浏览器位置改变,但不会再历史记录中生成新记录。在调用replace()方法之后,用户不能回到前一个页面。

<!DOCTYPE html>
<html>
<head>
	<title>You won't be able to get back here</title>
</head>
<body>
	<p>Enjoy this page for a second,because you won't be coming back here.</p>
	<script type="text/javascript">
		setTimeout(function(){
			location.replace("http://www.wrox.com/");
		},1000);
	</script>
</body>
</html>

如果将这个页面加载到浏览器中,浏览器就会在1秒钟后重新定向到www.wrox.com。然后,"后退"按钮将处于禁用状态,如果不重新输入完整的URL,则无法返回示例页面。

与位置有关的最后一个方法是reload(),作用是重新加载当前显示的页面。如果调用reload()时不传递任何参数,页面就会以最有效的方式重新加载。也就是说,如果页面自上次请求以来并没有改变过,页面就会以最有效的方式重新加载。也就是说,如果页面自上次请求以来并没有改变过,页面就会从浏览器缓存中重新加载。如果要强制从服务器重新加载,则需要像下面这样为该方法传递参数true。

location.reload();    //重新加载(有可能从缓存中加载)

location.reload(true); //重新加载(从服务器重新加载)

位于reload()调用之后的代码可能会也可能不会执行,这要取决于网络延迟或系统资源等因素。为此最好将reload()放在代码的最后一行。

navigator识别客户端浏览器的事实标准。虽然其他浏览器也通过其他方式提供了相同或相似的信息,但navigator对象却是所有支持JS的浏览器所共有的。与其他BOM对象的情况一样,每个浏览器中的navigator对象也都有一套自己的属性。下表列出了存在于所有浏览器中的属性和方法,以及支持它们的浏览器版本。

 表中的这些navigator对象的属性通常用于检测显示网页的浏览器类型。

检测插件

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

name:插件的名字

description:插件的描述

filename:插件的文件名。

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

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

//检测插件
function hasPlugin(name){
	name = name.toLowerCase();
	for(var i = 0;i<navigator.plugins.length;i++)
	{
		if(navigator.plugins[i].name.toLowerCase().indexOf(name)>-1){
			return true;
		}
	}
	return false;
}
//检测Flash
alert(hasPlugin("Flash"));
//检测QuickTime
alert(hasPlugin("QuickTime"));

这个 hasPlugin()函数接受一个参数:要检测的插件名。第一步是将传入的名称转换为小写形式,以便于比较。然后,迭代 plugins 数组,通过 indexOf()检测每个 name 属性,以确定传入的名称是否出现在字符串的某个地方。比较的字符串都使用小写形式可以避免因大小写不一致导致的错误。而传入的参数应该尽可能具体,以避免混淆。应该说,像 Flash 和 QuickTime 这样的字符串就比较具体了,不容易导致混淆。在 Firefox、Safari、Opera 和 Chrome 中可以使用这种方法来检测插件。

检测 IE 中的插件比较麻烦,因为 IE 不支持 Netscape 式的插件。在 IE 中检测插件的唯一方式就是使用专有的 ActiveXObject 类型,并尝试创建一个特定插件的实例。IE 是以 COM 对象的方式实现插件的,而 COM 对象使用唯一标识符来标识。因此,要想检查特定的插件,就必须知道其 COM 标识符。例如,Flash 的标识符是 ShockwaveFlash.ShockwaveFlash。知道唯一标识符之后,就可以编写类似下面的函数来检测 IE 中是否安装相应插件了。

//检测IE中的插件
function hasIEPlugin(name){
	try{
		new ActiveXObject(name);
		return true;
	}catch(ex){
		return false;
	}
}
//检测Flash
alert(hasPlugin("ShockwaveFlash.ShockwaveFlash"));
//检测QuickTime
alert(hasPlugin("QuickTime.QuickTime"));

在这个例子中,函数 hasIEPlugin()只接收一个 COM 标识符作为参数。在函数内部,首先会尝试创建一个 COM 对象的实例。之所以要在 try-catch 语句中进行实例化,是因为创建未知 COM 对象会导致抛出错误。这样,如果实例化成功,则函数返回 true;否则,如果抛出了错误,则执行 catch块,结果就会返回 false。例子最后检测 IE 中是否安装了 Flash 和 QuickTime 插件。

鉴于检测这两种插件的方法差别太大,因此典型的做法是针对每个插件分别创建检测函数,而不是使用前面介绍的通用检测方法。来看下面的例子。

//检测所有浏览器中的Flash
function hasFlash(){
	var result = hasPlugin("Flash");
	if(!result)
	{
		result = hasIEPlugin("ShockwaveFlash.ShockwaveFlash");
	}
	return result;
}
//检测所有浏览器中的QuickTime
function hasQuickTime(){
	var result = hasPlugin("QuickTime");
	if(!result){
		result = hasIEPlugin("QuickTime.QuickTime");
	}
	return result;
}
//检测Flash
alert(hasFlash());
//检测QuickTime
alert(hasQuickTime());

上面代码中定义了两个函数:hasFlash()和 hasQuickTime()。每个函数都是先尝试使用不针对IE 的插件检测方法。如果返回了 false(在 IE 中会这样),那么再使用针对 IE 的插件检测方法。如果IE 的插件检测方法再返回 false,则整个方法也将返回 false。只要任何一次检测返回 true,整个方法都会返回 true。

注册处理程序

Firefox 2为 navigator 对象新增了 registerContentHandler()和 registerProtocolHandler()方法。这两个方法可以让一个站点指明它可以处理特定类型的信息。随着 RSS 阅读器和在线电子邮件程序的兴起,注册处理程序就为像使用桌面应用程序一样默认使用这些在线应用程序提供了一种方式。

其中,registerContentHandler()方法接收三个参数:要处理的 MIME 类型、可以处理该 MIME类型的页面的 URL 以及应用程序的名称。举个例子,要将一个站点注册为处理 RSS 源的处理程序,可以使用如下代码。

navigator.registerContentHandler("application/rss+xml", "http://www.somereader.com?feed=%s", "Some Reader"); 

第一个参数是 RSS 源的 MIME 类型。第二个参数是应该接收 RSS 源 URL 的 URL,其中的%s 表示RSS 源 URL,由浏览器自动插入。当下一次请求 RSS 源时,浏览器就会打开指定的 URL,而相应的Web 应用程序将以适当方式来处理该请求。

类似的调用方式也适用于 registerProtocolHandler()方法,它也接收三个参数:要处理的协议(例如,mailto 或 ftp)、处理该协议的页面的 URL 和应用程序的名称。例如,要想将一个应用程序注册为默认的邮件客户端,可以使用如下代码。

navigator.registerProtocolHandler("mailto", "http://www.somemailclient.com?cmd=%s", "Some Mail Client"); 

这个例子注册了一个 mailto 协议的处理程序,该程序指向一个基于 Web 的电子邮件客户端。同样,第二个参数仍然是处理相应请求的 URL,而%s 则表示原始的请求。

screen对象

JavaScript 中有几个对象在编程中用处不大,而 screen 对象就是其中之一。screen 对象基本上只用来表明客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素宽度和高度等。每个浏览器中的 screen 对象都包含着各不相同的属性,下表列出了所有属性及支持相应属性的浏览器。

 

 这些信息经常集中出现在测定客户端能力的站点跟踪工具中,但通常不会用于影响功能。不过,有时候也可能会用到其中的信息来调整浏览器窗口大小,使其占据屏幕的可用空间,例如:

window.resizeTo(screen.availWidth, screen.availHeight);

前面曾经提到过,许多浏览器都会禁用调整浏览器窗口大小的能力,因此上面这行代码不一定在所有环境下都有效。
涉及移动设备的屏幕大小时,情况有点不一样。运行 iOS 的设备始终会像是把设备竖着拿在手里一样,因此返回的值是 768×1024。而 Android 设备则会相应调用 screen.width 和 screen.height 的值。

history对象

history 对象保存着用户上网的历史记录,从窗口被打开的那一刻算起。因为 history 是 window对象的属性,因此每个浏览器窗口、每个标签页乃至每个框架,都有自己的 history 对象与特定的window 对象关联。出于安全方面的考虑,开发人员无法得知用户浏览过的 URL。不过,借由用户访问过的页面列表,同样可以在不知道实际 URL 的情况下实现后退和前进。

使用 go()方法可以在用户的历史记录中任意跳转,可以向后也可以向前。这个方法接受一个参数,表示向后或向前跳转的页面数的一个整数值。负数表示向后跳转(类似于单击浏览器的“后退”按钮),正数表示向前跳转(类似于单击浏览器的“前进”按钮)。来看下面的例子。

//后退一页
history.go(-1);

//前进一页
history.go(1);

//前进两页
history.go(2);

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

//跳转到最近的 wrox.com 页面
history.go("wrox.com"); 
//跳转到最近的 nczonline.net 页面
history.go("nczonline.net"); 

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

//后退一页
history.back(); 
//前进一页
history.forward(); 

除了上述几个方法外,history 对象还有一个 length 属性,保存着历史记录的数量。这个数量包括所有历史记录,即所有向后和向前的记录。对于加载到窗口、标签页或框架中的第一个页面而言,history.length 等于 0。通过像下面这样测试该属性的值,可以确定用户是否一开始就打开了你的页面。

if (history.length == 0){ 
 //这应该是用户打开窗口后的第一个页面
} 

虽然 history 并不常用,但在创建自定义的“后退”和“前进”按钮,以及检测当前页面是不是用户历史记录中的第一个页面时,还是必须使用它。

猜你喜欢

转载自blog.csdn.net/baidu_29474379/article/details/85049380