标签:
ECMAScript是JavaScript的核心,但如果要在Web中使用JavaScript,那么BOM(浏览器对象模型)则无疑才是真正的核心。BOM提供了很多对象,用于访问浏览器的功能,这些功能与任何网页内容无关。多年来,缺少事实上的规范导致BOM及有意思又有问题,因为浏览器提供商会按照各自的想法随意去扩展它。于是,浏览器之间公有的对象就成为了事实上的标准。这些对象在浏览器中得以存在,很大程度上是由于它们提供了与浏览器的互操作性。W3C为了把浏览器中JavaScript最基本的部分标准化,已经将BOM的主要方面乃如了HTML5的规范中。
BOM的核心对象是window,它表示浏览器的一个实例,在浏览器中,window对象有双重角色,它既是通过JavaScript访问浏览器窗口的一个接口,有时ECMAScript规定的Global对象。这意味着在网页中定义的任何一个对象、变量和函数,都以window作为其Global对象,因此有权访问parseInt()等方法。
由于window对象同时扮演着ECMAScript中Global对象的角色,因此所有在全局作用域中声明的变量、函数都会变成window对象的属性和方法。来看下面的例子。
var age = 29; functionsayAge(){ 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 alert(delete window.age); //在IE<9时抛出错误,在其他浏览器都返回true alert(delete window.color); alert(window.age); alert(window.color);刚才使用var语句添加的window属性有一个名为[[Configurable]]的特性,这个特性的值被设置为false,因此这样定义的属性不可以通过delete操作符删除。IE8及更早版本在遇到使用delete删除window属性的语句时,不管该属性最初是如何创建的,都会抛出错误,以示警告。IE9及更高版本不会抛出错误。
另外,还要记住一件事:尝试访问未声明的变量会抛出错误,但是通过查询window对象,可以知道某个可能未声明的变量是否存在。例如:
//这里会抛出错误,因为oldValue未定义 var newValue =oldValue; //这里不会抛出错误,因为这是一次属性查询 var newValue = window.oldValue;
如果页面中包含框架,则每个框架都拥有自己的window对象,并且保存在frames集合中。在frames集合中,可以通过数值索引(从0开始,从左至右,从上到下)或者框架名称来访问相应的window对象。每个window对象都有一个name属性,其中包含框架的名称。下面是一个包含框架的页面:
<html> <head> <meta charset="UTF-8"> <title>FrameSet Example</title> </head> <frameset rows="160,*"> <frame src="frame.html" name="topFrame"></frame> <frameset cols="50%,50%"> <frame src="anotherframe.html" name="leftFrame"> <frame src="yetanotherframe.html" name="RightFrame"> </frameset> </frameset> </html>以上代码创建了一个框架集,其中一个框架居上,两个框架居下。对这个例子而言,可以通过window.frames[0]或者window.frames[“topFrame”]来引用上方的框架。不过,恐怕你最好使用top而非window来引用这些框架(例如,通过top.frames[0])。
top对象始终指向最高(最外)层的框架,也就是浏览器窗口。使用它可以确保在一个框架中正确地访问另一个框架。因为对于在一个框架中编写的任何代码来说,其中的window对象指向的都是那个框架的特定实例,而非最高层的框架,如下图,通过代码来访问前面例子中每个框架的不同方式:
与top相对的另一个额window对象是parent。顾名思义,parent对象始终指向当前框架的直接上层框架。在某些情况下,parent有可能等于top;但在没有框架的情况下,parent一定等于top(此时它们都等于window)。如:
<html> <head> <meta charset="UTF-8"> <title>FrameSet Example</title> </head> <frameset rows="160,*"> <frame src="frame.html" name="topFrame"></frame> <frameset cols="50%,50%"> <frame src="anotherframe.html" name="leftFrame"> <frame src="anotherframeset.html" name="RightFrame"> </frameset> </frameset> </html>这个框架集中的一个框架包含了另一个框架集,该框架集的代码如下所示。
<html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <frameset cols="50%,50%"> <frame src="red.html" name="rdFrame"> <frame src="blue.html" name="blueFrame"> </frameset> </html>浏览器在加载完第一个框架集以后,会继续将第二个框架加载到rightFrame中。如果代码位于redFrame(或blueFrame)中,那么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]。
在使用框架的情况下,浏览器中会存在多个Global对象。在每个框架中定义的全局变量会自动成为框架中window对象的属性。由于每个window对象都包含原生类型的构造函数,因此每个框架都有一套自己的构造函数,这些构造函数一一对应,但并不相等。例如,top.Object并不等于top.frames[0].Object。这个问题会影响到对跨框架传递的对象使用instanceof操作符。
用来确定和修改window对象位置的属性和方法有很多。IE、Safari、Opera和Chrome都提供了screenLeft和screenTop属性,分别用于表示矿口相对于屏幕左边和上边的位置。Firefox则在screenX和screenY属性中提供相同的窗口位置信息,Safari和Chrome也同时支持这两个属性。Opera虽然也支持screenX和screeY属性,但与screenLeft和screenTop属性并不对应,因此建议不要在Opera中使用它们。使用下面代码可以跨浏览器取得左边和上边的位置。
var leftPos = (typeof window.screenLeft == "number")? window.screenLeft:window.screenX; var topPos = (typeof window.screenLeft == "number")? window.screenTop:window.screenY;这个例子运用二元操作符首先确定screenLeft和screenTop属性是否存在,如果是(在IE、Safari、Opera和Chrome中),则取得这两个属性的值。如果不存在(在Firefox中),则取得screenX和screenY的值。
在使用这些值的过程中,还必须注意一些小问题。在IE、Opera和Chrome中,screenLeft和screenTop中保存的是从屏幕左边和上边由window对象表示的页面可见区域的距离。换句话说,如果window对象是最外层对象,而且浏览器窗口紧贴屏幕最上端——即y轴坐标为0,那么screenTop的值就是位于页面可见区域上方的浏览器工具栏的像素高度。但是,在Firefox和Safari中,screenX或screenTop中保存的是整个浏览器窗口相对于屏幕的坐标值,即在窗口的y轴坐标为0时返回0。
更让人捉摸不透的是,Firefox、Safari和Chrome始终返回页面中每个框架的top.screenX和top.screenY值。即使在页面由于被设置了外编剧而发生便宜的情况下,相对于window对象使用screenX和screenY每次也都会返回相同的值。而IE和Opera则会给出框架相对于屏幕边界的精确坐标值。
最终结果,就是无法在跨浏览器的条件下取得窗口左边和上边的精确坐标值。然而使用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)需要注意的是,这两个方法可能会被浏览器禁用;而且,在Opera和IE7(及更高版本)中默认就是禁用的。另外,这两个方法都不适用于框架,只能对最外层的window对象使用。
跨浏览器确定一个窗口的大小不是一件简单的事。IE9+、Firefox、Safari、Opera和Chrome均为此提供了4个属性:innerWidth、innerHeight、outerWidth和outerHeight。在IE9+、Safari和Firefox中,outerWidth和outerHeight返回浏览器窗口本身的尺寸(无论是从最外层的window对象还是从某个框架访问)。在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 == "SCC1Compat"){ 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的值。
对于移动设备,window.innerWidth和window.innerHeight保存着可见视口,也就是屏幕上可见页面区域的大小。移动IE浏览器不支持这些属性,但通过document.documentElement.clientWidth和document.documentElement.clientHeight提供了相同的信息。随着页面的缩放,这些值也会相应变化。
在其他移动浏览器中,document.documentElement度量是布局视口,即渲染后页面的实际大小(与视口不同,可见视口只是整个页面中的一小部分)。移动IE浏览器把布局视口的信息保存在document.body.clientWidth和document.body.clientHeight中。这些值不会随着页面的缩放变化。
由于与桌面浏览器间存在这些差异,最好是先检测一下用户是否早使用移动设备,然后再决定使用哪个属性。
另外使用resizeTo()和resizeBy()方法可以调整浏览器窗口的大小。这两个方法都接收两个参数,其中resizeTo()接收浏览器窗口的新宽度和新高度,而resizeBy()接收新窗口与原窗口的宽度和高度之差,如:
//调整到100x100 window.resizeTo(100,100); //调整到200x150 window.resizeBy(100,50); //调整到300x300 window.resizeTo(300, 300);需要注意的是,这两个方法与移动窗口位置的方法类似,也有可能被浏览器禁用;而且,在Opera和IE7(及更高版本)中默认就是禁用的。另外,这两个方法同样不适用于框架,而只能对最外层的window对象使用。
使用window.open()方法既可以导航到一个特定的URL,也可以打开一个新的浏览器窗口。这个方法可以接收4个参数:要加载的URL、窗口目标、一个特性字符串以及一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值。通常只须传递第一个参数,最后一个参数只在不打开新窗口的情况下使用。
如果为window.open()传递了第二个参数,而且该参数是已有窗口或框架的名称,那么就会在具有该名称的窗口或框架中加载第一个参数指定的URL。如:
//等同于<a href = "http://blog.csdn.net/goskalrie"target="topFrame"></a> window.open("http://blog.csdn.net/goskalrie" , "topFrame");调用这行代码,就如同用户点击了href属性为http://blog.csdn.net/goskalrie,target属性为“topFrame”的连接。如果有一个名叫“topFrame”的窗口或框架,就会在该窗口或框架中加载这个URL;否则,就会创建一个新窗口并将其命名为“topFrame”。此外,第二个参数也可以是下列任何一个特殊的窗口名称:_self、_parent、_top或_blank。
如果给window.open()传递的第二个参数并不是一个已经存在的窗口或框架,那么该方法就会根据在第三个参数位置上传入的字符串创建一个新窗口或新标签页。如果没有传入第三个参数,那么就会打开一个带有全部设置(工具栏、地址栏和状态栏等)的新浏览器窗口(或者打开一个新标签页——根据浏览器设置)。在不打开新窗口的情况下,会忽略第三个参数。
第三个参数是一个逗号分隔的设置字符串,表示在新窗口都显示哪些特性,下表列出了可以出现在这个字符串中的设置选项。
设置 |
值 |
说明 |
fullscreen |
yes或no |
表示浏览器窗口是否最大化。仅限IE |
height |
数值 |
表示新窗口的高度。不能小于100 |
left |
数值 |
表示新窗口的左坐标。不能是负值 |
location |
yes或no |
表示是否在浏览器窗口中显示地址栏。不同浏览器的默认值不同。如果设置为no,地址栏可能会隐藏,也可能会被禁用(取决于浏览器) |
menubar |
yes或no |
表示是否在浏览器中显示菜单栏。默认值为no |
resizable |
yes或no |
表示是否可以通过拖动浏览器窗口的边框改变其大小。默认值为no |
scrollbars |
yes或no |
表示是否如果内容在视口显示不下,是否允许滚动。默认值为no |
status |
yes或no |
表示是否在浏览器窗口中显示状态栏。默认值为no |
toolbar |
yes或no |
表示是否在浏览器窗口中显示工具栏。默认值为no |
top |
数值 |
表示新窗口的上坐标,不能是负值 |
width |
数值 |
表示新窗口的宽度。不能小于100 |
表中所列的全部分或全部设置选项,都可以通过逗号分隔的明智队列表来指定。其中,名值对以等号表示(注意,整个特性字符串中不允许出现空格),如下面的例子所示:
window.open("http://blog.csdn.net/goskalrie","topFrame", "height=400,width=400,top=10,left=10,resizable=yes");这行代码会打开一个新的可以调整大小的窗口,窗口初始大小为400x400像素,并且距屏幕上沿和左边各10像素。
window.open()方法会返回一个指向新窗口的引用。引用的对象与其他window对象大致相似,但可以对其进行更多控制。例如,有些浏览器在默认情况下可能不允许我们针对主浏览器窗口调整大小或移动位置,但却允许我们针对通过window.open()创建的窗口调整大小或移动位置。通过这个返回的对象,可以像操作其他窗口一样操作新打开的窗口,如:
var goser =window.open("http://blog.csdn.net/goskalrie" , "topFrame" , "height=400,width=400,top=10,left=10,resizable=yes"); //调整大小 goser.resizeTo(500,500); //移动位置 goser.moveTo(100, 100);调用close()方法还可以关闭新打开的窗口。
goser.close();
但是,这个方法仅适用于通过window.open()打开的弹出窗口。对于浏览器的主窗口,如果没有得到用户允许的情况下是不能关闭它的。不过,弹出窗口倒是可以调用top.close()在不经过用户允许的情况下关闭自己。弹出窗口关闭之后,窗口的引用仍然还在,但除了像下面这样检测其closed属性之外,已经没有其他用处了。
goser.close();
alert(goser.closed);//true
新创建的window对象有一个opener属性,其中保存着打开它的原始窗口对象。这个属性只在弹出窗口的最外层window对象(top)中有定义,而且指向调用window,open()的窗口或框架。如:
var goser =window.open("http://blog.csdn.net/goskalrie" ,"topFrame" , "height=400,width=400,top=10,left=10,resizable=yes");
alert(goser.opener== window);//true
虽然弹出窗口有一个指向打开它的原始窗口,但原始窗口中并没有这样的指针指向弹出窗口。窗口并不跟踪记录它们打开的弹出窗口,因此只能在必要的时候自己来手动实现跟踪。
有些浏览器(如IE8和Chrome)会在独立的进程中运行每个标签页。当一个标签页打开另一个标签页时,如果两个window对象之间需要彼此通信,那么新标签页就不能运行在独立的进程中。在Chrome中,将新创建的标签页的opener属性设置为null,即表示在单独的进程中运行新标签页,如:
var goser =window.open("http://blog.csdn.net/goskalrie" ,"topFrame" , "height=400,width=400,top=10,left=10,resizable=yes");
goser.opener = null;
将opener属性设置为null就是告诉浏览器新创建的标签页不需要与打开它的标签页通信,因此可以在独立的进程中运行。标签页之间的联系一旦切断,将没办法恢复。
曾经有一段时间,广告商在网页上使用弹出窗口达到了肆无忌惮的程度。他们经常把弹出窗口打扮成系统对话框的模样,引诱用户去点击其中的广告。由于看起来像是系统对话框,一般用户很难分辨是真是假,为了解决这个问题,有些浏览器开始在弹出窗口配置方面增加限制。
Windows XP SP2中的IE6对弹出窗口施加了多方面的安全限制,包括不允许在屏幕之外创建弹出窗口、不允许将弹出窗口移动到屏幕以外、不允许关闭状态栏等。IE7则增加了更多的安全限制,如不允许关闭地址栏、默认情况下允许移动弹出窗口或调整其大小。Firefox1从一开始就不支持修改状态栏,因此无论给window.open()传入什么样的特性字符串,弹出窗口中都会无一例外地显示状态栏。后来的Firefox3又强制始终在弹窗窗口中显示地址栏。Opera只会在祝浏览器窗口中打开弹出窗口,但不允许它们同时出现在可能与系统对话框混淆的地方。
此外,有的浏览器只根据用户操作来弹出窗口,这样一来,在页面尚未加载完成时调用window.open()的语句根本不会执行,而且还可能会将错误消息显示给用户。换句话说,只能通过单击或者击键来打开弹出窗口。
对于那些不是用户右移打开的弹出窗口,Chrome采取了不同的处理方式。它不会像其他浏览器那样简单地屏蔽这些弹出窗口,而是只显示它们的标题栏,并把它们放在浏览器窗口的右下角。
在打开计算机硬盘中的网页时,IE会解除对弹出窗口的某些限制。但是在服务器上执行这些代码会受到对弹出窗口的限制。
大多数浏览器都内置有弹出窗口屏蔽程序,而没有内置此类程序的浏览器,也可以安装Yahoo!ToolBar等带有内置屏蔽程序的实用工具。结果就是用户可以将绝大多数不想看到弹出窗口屏蔽掉。于是,在弹出窗口被屏蔽时,就应该考虑两种可能性。如果是浏览器内置的屏蔽程序阻止的弹出窗口,那么window.open()很可能会返回null。此时,只要检测这个返回的值就可以确定弹出窗口是否被屏蔽了,如:
var goser =window.open("http://blog.csdn.net/goskalrie" , "_blank"); if(goser == null){ alert("The popup was blocked!"); }如果是浏览器扩展或其他程序阻止的弹出框,那么window.open()通常会抛出一个错误。因此,要想准确地检测出弹出窗口是否被屏蔽,必须在检测返回值的同时,将对window.open()的调用封装在一个try-catch块中,如:
var blocked = false; try{ var goser = window.open("http://blog.csdn.net/goskalrie" , "_blank"); if(goser == null){ blocked = true; } }catch(ex){ blocked = true; } if(blocked){ alert("The popup was blocked!"); }在任何情况下,以上代码都可以检测出调用window.open()打开的弹出窗口是不是被屏蔽了。但要注意的是,检测弹出窗口是否被屏蔽只是一方面,它并不会阻止浏览器显示与被屏蔽的弹出窗口有关的消息。
JavaScript是单线程语言,但它允许通过设置超时值和间歇值来调度代码在特定的时刻执行。前者是在指定的时间过后执行代码,而后者则是每隔指定的时间就执行一次代码。
超时调用需要使用window对象的setTimeout()方法,它接受两个参数:要执行的代码和以毫秒表示的时间(即在执行代码前需要等待多少毫秒)。其中,第一个参数可以是一个包含JavaScript代码的字符串(就和在eval()函数中使用的字符串一样),也可以是一个函数。例如,下面对setTimeout()的两次调用都会在一秒钟后显示一个警告框。
//不建议传递字符串 setTimeout("alert('Hello World!')" , 1000); //推荐的调用方法 setTimeout(function(){ 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(),结果就跟什么也没发生一样。
超时调用的代码都是在全局作用域中执行的,因此函数中this的值在非严格模式下指向window对象,在严格模式下是undefined。
间歇调用与超时调用类似,只不过它会按照指定的时间间隔重复执行代码,直至间歇调用被取消或者页面被卸载。设置间歇调用的方法是setInterval(),它接受的参数与setTimeout()相同:要执行的代码(字符串或函数)和每次执行之前需要等待的毫秒数,如:
setInterval(function(){ document.getElementById("nowTime").innerHTML = new Date().toLocaleString(); },500);上面代码简单的在页面中显示了一个动态的时钟,与setTimeout()方法一样,不建议setInterval()的第一个参数为字符串,且setInterval()方法同样也会返回一个间歇调用Id,该Id可用于在将来某个时刻取消间歇调用。要取消尚未执行的调用,可以使用clearInterval()方法并传入相应的间歇调用Id。取消间歇调用的重要性要远远高于取消超时调用,因为在不加干涉的情况下,间歇调用将会一直执行到页面卸载。如:
functiongetCheckNo(){ var seconds = 121; var s = 60; var intervalId = setInterval(function(){ var disabled = true; s = Math.floor((seconds--)/2); document.getElementById("btnGetCheckNo").innerHTML="( " + s +" )" + "秒后重新发送"; if(seconds <= 0){ disabled = false; document.getElementById("btnGetCheckNo").innerHTML="获取验证码"; } if(disabled){ document.getElementById("btnGetCheckNo").setAttribute("disabled", "disabled"); }else{ document.getElementById("btnGetCheckNo").removeAttribute("disabled"); } } , 500); }<body> <div id="content"> <input type="text"/> <button id="btnGetCheckNo"onclick="getCheckNo()">获取验证码</button> </div> </body>上面的例子模拟了大多数注册页面中的发送验证码的功能,点击“获取验证码”后,倒计时将一直进行,这样是不符合要求的,这就需要在适合的时机将间歇调用给停掉,如下面的代码:
functiongetCheckNo(){ var seconds = 121; var s = 60; var intervalId = setInterval(function(){ var disabled = true; s = Math.floor((seconds--)/2); document.getElementById("btnGetCheckNo").innerHTML="( " + s +" )" + "秒后重新发送"; if(seconds <= 0){ disabled = false; clearInterval(intervalId); document.getElementById("btnGetCheckNo").innerHTML="获取验证码"; } if(disabled){ document.getElementById("btnGetCheckNo").setAttribute("disabled", "disabled"); }else{ document.getElementById("btnGetCheckNo").removeAttribute("disabled"); } } , 500); }上面的例子中,代码行#10,在倒计时到0秒的时候停止间歇调用。一般认为,使用超时调用来模拟间歇调用是一种最佳模式。在开发环境下,很少使用真正的间歇调用,原因是后一个间歇调用可能会在前一个间歇调用结束之前开启。可以将上面例子中禁用按钮的代码去掉,打开页面后多次连续点击“获取验证码”按钮,很明显的看出上面描述的间歇调用的缺点。但是,像下面这样使用超时调用,则完全可以避免这一点,所以,最好不要使用间歇调用。
var seconds = 121; var s = 60; functioncount(){ s = Math.floor((seconds--)/2); document.getElementById("btnGetCheckNo").innerHTML="( " + s +" )" + "秒后重新发送"; if(seconds <= 0){ document.getElementById("btnGetCheckNo").innerHTML="获取验证码"; document.getElementById("btnGetCheckNo").removeAttribute("disabled"); }else{ setTimeout(count, 500); } } functiongetCheckNo(){ document.getElementById("btnGetCheckNo").setAttribute("disabled", "disabled"); setTimeout( count, 500); }
浏览器通过alert()、confirm()和prompt()方法可以调用系统对话框向用户显示消息。系统对话框与浏览器中显示的网页没有关系,也不包含HTML。它们的外观由操作系统及(或)浏览器设置决定,而不是由CSS决定。此外,通过这几个方法打开的对话框都是同步和模态的。也就是说,显示这些对话框的时候代码会停止执行,而关掉这些对话框后代码会恢复执行。
经常使用的是alert()方法,这个方法接受一个字符串 并将其显示给用户。具体来说,调用alert()方法的结果就是向用户显示一个系统对话框,其中包含指定的文本和一个OK(“确定”)按钮。
confirm()方法生成的对话框包含两个按钮Ok(“确定”)和Cancel(“取消”),该方法返回一个布尔值,用户点击Ok时返回true,点击Cancel或直接关闭对话框返回false:
var flag =confirm("Are Usure?"); if(flag){ alert("U click Ok."); }else{ alert("U click cancel or close."); }prompt()也会弹出一个对话框,用于用户输入一些文本。对话框中除了显示确定和取消键之外,还会显示一个文本输入域,以供用户在其中输入内容。prompt()方法接受两个参数:要显示给用户的文本提示和文本输入域的默认值(可以是一个空字符串)。如果用户点击了确定按钮,则prompt()返回文本输入域的值;如果用户点击了取消按钮或直接关闭对话框则返回null,如:
var result =prompt("What'syour name?" , ""); if(result != null){ alert("Welcome " + result); }综上,这些系统对话框很适合向用户显示消息并请用户做出决定。由于不涉及HTML、CSS或JavaScript,因此它们是增强Web应用程序的一种便捷方式。
除了上述三种对话框外,GoogleChrome浏览器还引用了一种新特性。如果当前脚本在执行过程中会打开两个或多个对话框,那么从第二个对话框开始,每个对话框中都会显示一个复选框,以便用户阻止后续的对话框显示,除非用户刷新页面。
还有两个可以on各国JavaScript打开的对话框,即“查找”和“打印”。这两个对话框都是异步显示的,能够将控制权立即交还给脚本。这两个对话框与用户通过浏览器菜单的“查找”和“打印”命令打开的对话框相同。而在JavaScript中可以像下面这样通过window对象的find()和print()方法打开它们:
//显示“打印”对话框 window.print(); //显示“查找”对话框 window.find();这两个方法同样不会就用户在对话框中的操作给出任何信息,因此它们的用处有限。另外,既然这两个对话框是异步显示的,那么Chrome的对话框计数器就不会将它们计算在内,所以它们也不会受用户禁用后续对话框显示的影响。
location是最有用的BOM对象之一,它提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功能。事实上,location对象是很特别的一个对象,因为它既是window对象的属性,也是document对象的属性;换句话说,window.location和document.location引用的是同一个对象。location对象的用处不知表现在它保存着当前文档的信息,还表现在它将URL解析为独立的片段,让开发人员可以通过不同的属性访问这些片段。下表列出了location对象的所有属性(注:省略了每个属性前面的location前缀)。
属性名 |
例子 |
说明 |
hash |
“#contents” |
返回URL中的hash(#号后跟零或多个字符),如果URL中不包含散列,则返回空字符串。 |
host |
“www.wrox.com:80” |
返回服务器名称和端口号(如果有) |
hostname |
“www.wrox.com” |
返回不带端口号的服务器名称 |
href |
“http:/www.wrox.com” |
返回当前加载页面的完整URL。而location对象的toString()方法也返回这个值 |
pathname |
“”/WileyCDA/ |
返回URL中的目录和(或)文件名 |
port |
“8080” |
返回URL中指定的端口号。如果URL中不包含端口号,则这个属性返回空字符串 |
protocol |
“http:” |
返回页面使用的协议。通常是“http”或“https” |
search |
“?q=javascript” |
返回URL的查询字符串。这个字符串以问号开头 |
查询字符串参数
虽然通过上面的属性可以访问到location对象的大多数信息,但其中访问URL包含的查询字符串的属性并不方便。尽管location.search返回从问号到URL末尾的所有内容,但却没有办法逐个访问其中的每个查询字符串参数。为此,可以像下面这样创建一个函数,用以解析查询字符串,然后返回包含所有参数的一个对象:
functiongetQueryStringArgs(){ //取得查询字符串并去掉开头的问号 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对象可以通过很多方式来改变浏览器的位置。首先,也是最常用的方式,就是使用assign()方法并为其传递一个URL,如:
location.assign("http://blog.csdn.net/goskalrie");
这样,就可以立即打开新URL并在浏览器的历史记录中生成一条记录。如果是将location.href或window.location设置为一个URL值,也会以该值调用assign()方法。例如,下列两行代码与显示调用assign()方法的效果完全一样:
window.location = "http://blog.csdn.net/goskalrie";
location.href = "http://blog.csdn.net/goskalrie";
在这些改变浏览器位置的方法中,最常用的是设置location.href属性。
另外,修改location对象的其他属性也可以改变当前加载的页面。下面的例子展示了通过将hash、search、hostname、pathname和port属性设置为新值来改变URL。
//假设初始URL为 http://my.csdn.net/ //将URL修改为 http://my.csdn.net/#start location.hash= "#start"; //将URL修改为 http://my.csdn.net/?q=javascript#start location.search = "?q=javascript"; //将URL修改为 http://blog.csdn.net/?q=javascript#start location.hostname = "blog.csdn.net"; //将URL修改为http://blog.csdn.net/Goskalrie?q=javascript#start location.pathname = "Goskalrie"; //将URL修改为http://blog.csdn.net:8080/Goskalrie?q=javascript#start(实际上是没有该URL的) location.port = 8080;
每次修改location的属性(hash除外),页面都会以新URL重新加载。当通过上述任何一种方式修改URL之后,浏览器的历史记录中就会生成一条新记录,因此用户通过单击“后退”按妞妞都会导航到前一个页面。要禁用这种行为,可以使用replace()方法。这个方法只接受一个参数,即要导航到的URL;结果虽然会导致浏览器位置改变,但不会在历史记录中生成新记录。在调用replace()方法之后,用户不能回到前一个页面。
与位置有关的最后一个方法是reload(),作用是重新加载当前显示的页面。如果调用reload()时不传递任何参数,也买年就会以最有效的方式重新加载。也就是说,如果页面自上次请求以来并没有改变过,页面就会从浏览器缓存中重新加载。如果要强制从服务器加载,则需要为该方法传递参数true。
位于reload()调用之后的代码可能会也可能不会执行,这取决于网络延迟或系统资源等因素。为此,最好将reload()放在代码的最后一行。
最早由Netscape Navigator 2.0引入的navigator对象,现在已经称为识别客户端浏览器的事实标准。虽然其他浏览器也通过其他方式提供了相同或相似的信息(例如,IE中的window.clientInfomation和Opera中的window.opera),但navigator对象却是所有支持JavaScript的浏览器所公有的。与其他BOM对象的情况一样,每个浏览器中的navigator对象也有一套自己的属性,下表列出了存在于所有浏览器中的属性和方法。
属性或方法 |
说明 |
appCodeName |
浏览器的名称。通常都是Mozilla,即使在非Mozilla浏览器中也是如此 |
appMinorVersion |
次版本信息 |
appName |
完整的浏览器名称 |
appVersion |
浏览器的版本。一般不与实际的浏览器版本对应 |
buildID |
浏览器编译版本 |
cookieEnabled |
表示cookie是否启用 |
cpuClass |
客户端计算机中使用的CPU类型(x86、68K、Alpha、PPC或Other) |
javaEnabled() |
表示当前浏览器是否启用了java |
language |
浏览器的主语言 |
mimeTypes |
在浏览器中注册的MIME类型数组 |
onLine |
表示浏览器是否连接到了因特网 |
opsProfile |
似乎早就不用了,早不到相关文档 |
oscpu |
客户端计算机的操作系统或使用的CPU |
Platform |
浏览器所在的系统平台 |
plugins |
浏览器中安装的插件信息的数组 |
preferencs() |
设置用户的首选项 |
product |
产品名称 |
productSub |
关于产品的次要信息 |
registerContentHandler |
针对特定的MIME类型将一个站点注册为处理程序 |
registerProtocolHandler() |
针对特定的协议将一个站点注册为处理程序 |
securityPolicy |
已经废弃 |
systemLanguage |
操作系统的语言 |
taintEnabled() |
已经废弃 |
userAgent |
浏览器的用户代理字符串 |
userLanguage |
操作系统的默认语言 |
userProfile |
借以访问用户个人信息的对象 |
vendor |
浏览器的品牌 |
vendorSub |
有关供应商的次要信息 |
检测浏览器中是否安装了特定的插件是一种最常见的检测例程。对于非IE浏览器,可以使用plugins数组来达到这个目的。该数组中的每一项都包含下列属性。
name:插件的名字。
description:插件的描述。
filename:插件的文件名。
length:插件所处理的MIME类型数量。
一般来说,name属性中会包含检测插件必须的所有信息,但有时候也不完全如此。在检测插件时,需要像下面这样循环迭代每个插件并将插件的name与给定的名字进行比较。
//检测插件(在IE中无效) functionhasNotIEPlugin(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; } //检测IE中的插件 functionhasIEPlugin(name){ try{ new ActiveXObject(name); return true; }catch(e){ return false; } } functionisIE(){ return navigator.userAgent.toLowerCase().match(/rv:([\d.]+)\) like gecko/)?true:false; } functionhasPlugin(name){ if(isIE){ return hasIEPlugin(name); }else{ return hasNotIEPlugin(name); } } alert(hasPlugin("ShockwaveFlash.shockwaveFlash"));检测IE中的插件比较麻烦,因为IE不支持Netscape式的插件.在IE中检测插件的唯一方式就是使用专有的ActiveXObject类型,并尝试创建一个特定插件的实例.IE是以COM对象的方式实现插件的,而COM对象使用唯一标识符来标识.因此,要想检查特定的插件,就必须知道其COM标识符.例如,Flash的标识符是ShockwaveFlash.shockwaveFlash.知道其唯一标识符之后,就可以编写类似上面的函数检测IE中是否安装相应插件了。
在Web编程中,浏览器兼容是必不可少的,判断浏览器类型和版本的方法也各有各的实现,下面是一种:
$(function () { var Sys = {}; var ua = navigator.userAgent.toLowerCase(); var s; (s = ua.match(/rv:([\d.]+)\) like gecko/))? Sys.ie = s[1] : (s = ua.match(/msie ([\d.]+)/)) ? Sys.ie =s[1] : (s = ua.match(/firefox\/([\d.]+)/)) ?Sys.firefox = s[1] : (s = ua.match(/chrome\/([\d.]+)/)) ?Sys.chrome = s[1] : (s = ua.match(/opera.([\d.]+)/)) ?Sys.opera = s[1] : (s = ua.match(/version\/([\d.]+).*safari/))? Sys.safari = s[1] : 0; if (Sys.ie) $('span').text('IE: ' + Sys.ie); if (Sys.firefox) $('span').text('Firefox: ' + Sys.firefox); if (Sys.chrome) $('span').text('Chrome: ' + Sys.chrome); if (Sys.opera) $('span').text('Opera: ' + Sys.opera); if (Sys.safari) $('span').text('Safari: ' + Sys.safari); });
plugins集合有一个名叫refresh()的方法,用于刷新plugins以反映最新安装的插件。这个方法接收一个参数:表示是否应该重新加载页面的一个布尔值。如果将这个值设置为true,则会重新加载包含插件的所有页面;否则,只更新plugins集合,不重新加载页面。
Firefox2为navigator对象新增了registerContentHandler()和registerProtocolHandler()方法(这两个方法是在HTML5中定义的)。这两个方法可以让一个站点指明它可以处理特定类型的信息。随着RSS阅读器和在线电子邮件程序的兴起,注册处理程序就为像使用桌面应用程序一样默认使用这些在线应用程序提供了一种方式。
其中,registerContentHandler()方法接收三个参数:要处理的MIME类型、可以处理该MIME类型的页面的URL以及应用程序的名称。举个例子,要将一个站点注册为处理RSS源的处理程序,可以使用如下代码:
navigator.registerContentHandler(“application/rss+xml”,http://www.somereader.com?feed=%s,”SomeReader”);
第一个参数是RSS源的MIME类型。第二个参数是应该接收RSS源URL的URL,其中%s表示RSS源URL,由浏览器自动插入。当下一次请求RSS源时,浏览器就会打开指定的URL,而相应的Web程序将以适当方式来处理该请求。
类似的调用方式也适用于registerProtocolHandler()方法,它也接收三个参数:要处理的协议(如,mailto或ftp)、处理该协议的页面的URL和应用程序的名称。例如,要想将一个应用程序注册为默认的邮件客户端,可以使用如下代码。
navigator.registerProtocolHandler(“mailto”,http://www.somemailclient.com?cmd=%s,”SomeMail Client”);
这个例子注册了一个mailto协议的处理程序,该程序指向一个基于Web的电子邮件客户端。同样第二个参数仍然是处理相应请求的URL,而%s则表示原始的请求。
JavaScript中有几个对象在编程中用处不大,而screen对象就是其中之一。screen兑现基本上只用来表名客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素宽度和高度等。每个浏览器中的screen兑现格斗包含着各不相同的属性,下表列出了所有属性及支持相应属性的浏览器。
属性 |
说明 |
IE |
Firefox |
Safari/ Chrome |
Opera |
availHeight |
屏幕的像素高度减系统部件高度之后的值(只读) |
√ |
√ |
√ |
√ |
availLeft |
未被系统部件占用的最左侧的像素值(只读) |
|
√ |
√ |
|
availTop |
屏幕的像素宽度减系统部件宽度之后的值(只读) |
|
√ |
√ |
|
availWidth |
屏幕的像素宽度减系统部件宽度之后的值(只读) |
√ |
√ |
√ |
√ |
bufferDepth |
读、写用于呈现屏外位图的位数 |
√ |
|
|
|
colorDepth |
用于表现颜色的位数,多数系统都是32(只读) |
√ |
√ |
√ |
√ |
deviceXDPI |
屏幕实际的水平DPI(只读) |
√ |
|
|
|
deviceYDPI |
屏幕实际的垂直DPI(只读) |
√ |
|
|
|
fontSmoothingEnabled |
表示是否启用了字体平滑(只读) |
√ |
|
|
|
height |
屏幕的像素高度 |
√ |
√ |
√ |
√ |
left |
当前屏幕距左边的像素距离 |
|
√ |
|
|
logicalXDPI |
屏幕逻辑的水平DPI(只读) |
√ |
|
|
|
logicalYDPI |
屏幕逻辑的垂直DPI(只读) |
√ |
|
|
|
pixelDepth |
屏幕的位深(只读) |
|
√ |
√ |
√ |
top |
当前屏幕距上边的像素距离 |
|
√ |
|
|
updateInterval |
读、写以毫秒表示的屏幕刷新时间间隔 |
√ |
|
|
|
width |
屏幕的像素宽度 |
√ |
√ |
√ |
√ |
这些信息经常出现在测定客户端能力的站点跟中工具中,但通常不会用于影响功能。不过,有时候也可能会用到其中的信息来调整浏览器窗口大小,使其占据屏幕的可用空间,例如:
window.resizeTo(screen.availWidth,screen.availHeight);
前面曾经提到过,许多浏览器都会禁用调整浏览器窗口大小的能力,因此上面这行代码不一定在所有环境下都有效。
设计移动设备的屏幕大小时,情况有点不一样。运行iOS的设备始终会像是把设备竖着拿在手里一样,因此返回的值是768x1024。而Android设备则会相应调用screen.width和screen.height的值。
history对象保存着用户上网的历史记录,从窗口被打开的那一刻算起。因为histor是window对象的属性,因此每个浏览器窗口、每个标签页乃至每个框架,都有自己的history对象与特定的window对象关联。出于安全方面的考虑,开发人员无法得知用户浏览过的URL。不过,借由用户访问过的页面列表,同样可以在不知道实际情况URL的情况下实现后退和前进。
使用go()方法可以在用户的历史记录中任意跳转,可以向后也可以向前。这个方法接受一个参数,表示向后或向前的页面数的一个整数值。负数表示向后跳转(类似于单击浏览器的“后退”按钮),正数表示向前跳转(类似于单击浏览器的“后退”按钮)。如:
//后退一页
history.go(-1);
//前进一页
history.go(1);
//后退两页
history.go(-2);
也可以给go()方法传递一个字符串参数,此时浏览器会跳转到历史记录中包含该字符串的第一个位置——可能后退也可能前进,具体要看那个位置最近。如果历史记录中不包含该字符串,那么这个方法什么也不做。
另外,还可以使用两个简写方法back()和forward()来代替go()。顾名思义,这两个方法可以模仿浏览器的“后退”和“前进”按钮。
除了上述几个方法外,history对象还有一个length属性,保存着历史记录的数量。这个数量包括所有历史记录,即所有向后和向前的记录。对于加载到窗口、标签页或框架中的第一个页面而言,history.length等于0。标签:
原文地址:http://blog.csdn.net/goskalrie/article/details/51721412