8.1 window对象
BOM的核心对象是window,它表示浏览器的一个实例.在浏览器中,window即是通过JavaScript访问浏览器窗口的一个接口,又是ECMAScript规定的Global对象.这意味着在网页中定义的任何一个对象,变量和函数,都以window作为其Global对象,因此有权访问parseInt()等方法.
8.1.1 全局作用域
所有在全局使用域中声明的变量,函数都会变成window对象的属性和方法.
var age=29; function sayAge(){ console.log(this.age); } console.log(window.age);//29 sayAge();//29 window.sayAge();//29
由于sayAge()存在于全局作用域中,因此this.age被映射到window.age.
定义全局变量与在window对象上直接定义属性还是有一点差别:全局变量不能通过delete操作符删除,而直接在window对象上的定义的属性可以.
var age=29; window.color="red"; //在IE<9时抛出错误,在其他所有浏览器中都返回false delete window.age; //在IE<9时抛出错误,在其他所有浏览器中都返回true delete window.color; console.log(window.age);//29 console.log(window.color);//undefined
上面使用var语句添加给window属性有一个名为[[Configurable]]的特性,这个特性的值被设置为false,因此这样定义的属性不可以通过delete操作符删除.
IE8及更早版本在遇到使用delete删除window属性的语句时,不管该属性最初是如何创建的,都会抛出错误,以示警告.IE9及更高版本不会抛出错误.
注意:尝试访问未声明的变量会抛出错误,但是通过查询window对象,可以知道某个可能未声明的变量是否存在.
//这里会报错 var newValue=oldValue;//Uncaught ReferenceError: oldValue is not defined //这里不会报错,因为这是一次属性查询 var newValue=window.oldValue; console.log(newValue);//undefined
Window Mobile平台的IE浏览器不允许通过window.property=value之类的形式,直接在window对象上创建新的属性或方法.可是,在全局作用域中声明的所有变量和函数,照样会变成window对象的成员.
8.1.2 窗口关系及框架
如果页面中包含框架,则每个框架都拥有自己的window对象,并且保存在frames集合中.
每个window对象都有一个name属性,其中包含框架的名称.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <frameset rows="160,*"> <frame src="frame.htm" name="topFrame"> <frameset cols="50%,50%"> <frame src="anotherframe.htm" name="leftFrame"> </frame> <frame src="yetanotherframe.htm" name="rightFrame"> </frame> </frameset> </frameset> </html>
以上代码创建了一个框架集,其中一个框架居上,两个框架居下.对这个例子而言可以通过window.frames[0]或者window.farmes["topFrame"]来引用上方的框架.
top对象始终指向最高(最外)层的框架,也就是浏览器窗口.
对于在一个框架中编写的任何代码来说,其中的window对象指向的都是那个框架的特定实例,而非最高层的框架.
与top相对的另一个window对象是parent.顾名思义,parent(父)对象始终指向当前框架的直接上层框架.
在某些情况下,parent有可能等于top;但在没有框架的情况下,parent一定等于top(此时它们都等于window).
注意,除非最高层窗口是通过window.open()打开的,否则其window对象的name属性不会包含任何值.
与框架有关的最后一个对象是self,它始终指向window;实际上,selft和window对象可以互换使用.引入self对象的目的只是为了与top和parent对象对应起来,因此它不格外包含其他值.
所有这些对象都是window对象的属性,可以通过window.parent,window.top等形式来访问.同时,这也意味着可以将不同层次的window对象连缀起来,例如window.parent.parent.frames[0].
在使用框架的情况下,浏览器中会存在多个Global对象.在每个框架中定义的全局变量会自动成为框架中window对象的属性.由于每个window对象都包含原生类型的构造函数,因此每个框架都有一套自己的构造函数,这些构造函数一一对应,但并不相等.例如,top.Object并不等于top.frames[0].Object.
8.1.3 窗口位置
IE,Safari,Opera和Chrome都提供screenLeft和screenTop属性,分别表示窗口相对于屏幕左边和上边的位置.
FF中为screenX和screenY,Safari和Chrome也支持这两个属性.Opera虽支持不过并不对应.
使用下列代码可以跨浏览器取得窗口左边和上边的位置.
var leftPos=(typeof window.screenLeft=="number")?window.screenLeft:window.screenX; var topPos=(typeof window.screenTop=="number")?window.screenTop:window.screenY;
这里各个浏览器间的兼容问题较多,需多加注意.
8.1.4 窗口大小
IE9+,FF,Safari,Opera,Chrome为确定一个窗口大小提供了4个属性:innerWidth,innerHeight,outerWidth,outerHeight.
此处各个浏览器对属性取得值会有不同,需多在各浏览器上练习.
虽然最终无法确定浏览器窗口本身的大小,却可以取得页面视口的大小.
var pageWidth=window.innerWidth; var 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; } }
8.1.5 导航和打开窗口
使用window.open()方法既可以导航到一个特定的URL,也可以打开一个新的浏览器窗口.这个方法可以接收4个参数:要加载的URL,窗口目标,一个特性字符串以及一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值.通常只须传递第一个参数,最后一个参数只在不打开新窗口的情况下使用.
如果为window.open()传递了第二个参数,而且该参数是已有窗口或框架的名称,那么就会在具有该名称的窗口或框架中加载第一个参数指定的URL.
//等于于<a href="http://www.baidu.com" target="topFrame"></a> window.open("http://www.baidu.com/","topFrame");
第二个参数也可以是_self,_parent,_top或_blank中任何一个.
1.弹出窗口
window.open()中第二个参数并不是一个已经存在的窗口或框架,那么该方法就会根据在第三个参数位置上传入的字符创建一个新窗口或新标签页.如果没有第三个参数,那么就会打开一个带有全部默认设置(工具栏,地址栏和状态栏等)的新浏览器窗口(或者打开一个新标签页-根据浏览器设置).在不打开新窗口的情况下,会忽略第三个参数.
第三个参数是一个逗号分隔的设置字符串,表示在新窗口中都显示哪些特性.
设置 | 值 | 说明 |
fullscreen | yes或no | 表示浏览器窗口是否最大化.仅限IE |
height | 数值 | 表示新窗口的高度.不能小于100 |
left | 数值 | 表示新窗口的左坐标.不能是负值 |
location | yes或no | 表示是否在浏览器窗口中显示地址栏.不同浏览器的默认值不同.如果设置为no,地址栏可能会隐藏,也可能会被禁用(取决于浏览器) |
menubar | yes或no | 表示是否在浏览器窗口中显示菜单栏.默认为no |
resizable | yes或no | 表示是否可以通过拖动浏览器窗口的边框改变其大小.默认值为no |
scrollbas | yes或no | 表示如果内容在视口中显示不下,是否允许滚动.默认值为no |
status | yes或no | 表示是否在浏览器窗口中显示状态栏.默认值为no |
toolbar | yes或no | 表示是否在浏览器窗口中显示工具栏.默认值为no |
top | 数值 | 表示新窗口的上坐标.不能是负值 |
width | 数值 | 表示新窗口的宽度.不能小于100 |
表中所列的部分或全部设置选项,都可以通过逗号分隔的名值对列表来指定.其中,名值对以等号表示(注意,整个特性字符中不允许出现空格).
window.open("http://www.baidu.com","baiduwindow","height=400,width=400,top=10,left=10,resizable=yes");
window.open()方法会返回一个指向新窗口的引用.
var baiduWin=window.open("http://www.baidu.com","baiduwindow","height=400,width=400,top=10,left=10,resizable=yes"); //调整大小 baiduWin.resizeTo(500,500); //移动位置 baiduWin.moveTo(100,100);
调用close()方法还可以关闭新打开的窗口.但是这个方法仅适用于通过window.open()打开的弹出窗口.
对于浏览器的主窗口,如果没有得到用户的允许是不能关闭它的.不过弹出窗口倒是可以调用top.close()在不经用户允许的情况下关闭自己.弹出窗口关闭之后,窗口的引用仍然还在,但除了检测其closed属性外,已经没有其他用处了.
baiduWin.close();
alert(baiduWin.closed)
不过这里自己在多个浏览器下检测的结果并不相同.
新创建的window对象有一个opener属性,其中保存着打开它的原始窗口对象.这个属性只在弹出窗口中的最外层window对象(top)中有定义,而且指向调用window.open()的窗口或框架.
var baiduWin=window.open("http://www.baidu.com","baiduwindow","height=400,width=400,top=10,left=10,resizable=yes"); alert(baiduWin.opener==window);//true
在Chrome中,将新创建的标签页的opener属性设置为null,即表示在单独的进程中运行新标签页.
var baiduWin=window.open("http://www.baidu.com","baiduwindow","height=400,width=400,top=10,left=10,resizable=yes"); baiduWin.opener=null;
将opener属性设置为null就是告诉浏览器新创建的标签页不需要与打开它的标签页通信,因此,可以在独立的进程中运行.标签页之间的联系一旦切断,将没有办法恢复.
2.安全限制
IE6不允许在屏幕之外创建弹出窗口,不允许将弹出窗口移动到屏幕以外,不允许关闭状态栏等.IE7增加了更多安全限制,如不允许关闭地址栏,默认情况下不允许移动弹出窗口或调整其大小.FF1从一开始就不支持修改状态栏,因此无论给window.open()传入什么样的特性字符串,弹出窗口中都会无一例外地显示状态栏.后来,FF3又强制始终在弹出窗口中显示地址栏.Opera只会在主浏览器窗口中打开弹出窗口,但不允许它们出现在可能与系统对话框混淆的地方.
3.弹出窗口屏蔽程序
在弹出窗口被屏蔽时,应该考虑两种可能性.如果是浏览器内置的屏蔽程序阻止的弹出窗口,那么window.open()很可能会返回null.
此时,只要检测这个返回的值就可以确定弹出窗口是否被屏蔽.
var baiduWin=window.open("http://www.baidu.com","baiduwindow","height=400,width=400,top=10,left=10,resizable=yes"); if(baiduWin==null){ alert("the popup was blocked!"); }
如果是浏览器扩展或其他程序阻止的弹出窗口,那么window.open()通常会抛出一个错误.因此,要想准确地检测出弹出窗口是否被屏蔽,必须在检测返回值的同时,将对window.open()的调用封装在一个try-catch块中.
var blocked=false; try{ var baiduWin=window.open("http://www.baidu.com","baiduwindow","height=400,width=400,top=10,left=10,resizable=yes"); if(baiduWin==null){ blocked=true; } }catch (ex){ blocked=true; } if(blocked){ alert("the popup was blocked!"); }
8.1.6 间歇调用和超时调用
JavaScript是单线程语言,但它允许通过设置超时值和间歇时间值来调度代码在特定的时刻执行.
前者是在指定的时间过后执行代码,后者是每隔指定的时间执行一次代码.
超时调用需要使用window对象的setTimeout()方法,它接受两个参数:要执行的代码和以毫秒表示的时间(即在执行代码前需要等待多少毫秒).
第一个参数可以是一个包含js代码的字符串(不建议)也只可以是一个函数,第二个参数是一个表示等待多长时间的毫秒数,但经过该时间后指定的代码不一定会执行.因为JS是单线程的,执行的代码有一个任务队列,它们按顺序添加执行.如果队列是空的,添加的代码会立即执行,如果不是空的,那么它会等它前面的代码执行完之后再执行.
调用setTimeout()之后,该方法会返回一个数值ID,表示超时调用.这个超时调用ID是计划执行代码的唯一标识符,可以通过它来取消超时调用.要取消尚未执行的超时调用计划,可以调用clearTimeout()方法并将相应的超时调用ID作为参数传递给它.
超时调用的代码都是在全局作用域中执行的,因此函数中this的值在非严格模式下指向window对象,在严格模式下是undefined.
间歇调用与超时调用类似,只不过它会按照指定的时间间隔重复执行代码,直至间歇调用被取消或者页面被制裁.
在开发环境下,很少使用真正的间歇调用,原因是后一个间歇调用可能会在前一个间歇调用结束之前启动.
8.1.7 系统对话框
浏览器通过alert(),confirm(),prompt()方法可以调用系统对话框向用户显示信息.系统对话框与在浏览器中显示的网页没有关系,也不包括HTML.显示这些对话框的代码会停止执行,而关掉这些对话框后代码又会恢复执行.
alert() "警告"对话框
confirm() “确认”对话框
为了确定用户是单击了confirm()的OK还是Cancel,可以检测confirm()方法返回的布尔值:true为单击了ok,false表示单击了cancel.
prompt() "提示”框,用于提示用户输入一些文本