ECMAScript是JavaScript的核心,但如果要在 Web中使用 JavaScript,那么 BOM(浏览器对象模
型)则无疑才是真正的核心。
BOM 的核心对象是 window ,它表示浏览器的一个实例。
在浏览器中, window 对象有双重角色,
它既是通过 JavaScript 访问浏览器窗口的一个接口,又是 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 ,最终显示的仍然是正确
的结果。
抛开全局变量会成为 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 属性的语句时,不管该属性最初是如何创建的,都会抛出错误,以示警告。IE9 及更高版
本不会抛出错误。
另外,还要记住一件事:尝试访问未声明的变量会抛出错误,但是通过查询 window 对象,可以知
道某个可能未声明的变量是否存在。例如:
/这里会抛出错误,因为 oldValue 未定义
var newValue = oldValue;
//这里不会抛出错误,因为这是一次属性查询
//newValue 的值是 undefined
var newValue = window.oldValue;
如果页面中包含框架,则每个框架都拥有自己的 window 对象,并且保存在 frames 集合中。
在 frames
集合中,可以通过数值索引(从 0 开始,从左至右,从上到下)或者框架名称来访问相应的 window 对
象。每个 window 对象都有一个 name 属性,其中包含框架的名称。
下面是一个包含框架的页面:
Frameset Example
以上代码创建了一个框架集,其中一个框架居上,两个框架居下。对这个例子而言,可以通过
window.frames[0] 或者 window.frames[“topFrame”] 来引用上方的框架。(例如,通过 top.frames[0] )。
我们需要知道, top 对象始终指向最高(最外)层的框架,也就是浏览器窗口。
使用它可以确保在一个
框架中正确地访问另一个框架。
因为对于在一个框架中编写的任何代码来说,其中的 window 对象指向
的都是那个框架的特定实例,而非最高层的框架。
现在我们来看看通过代码来访问前面
例子中每个框架的不同方式。
框架集的第一个框架 也就是命名topFrame这个
1.window.frames[0]
2.window.frames["topFrame"]
3.top.frames[0]
4.top.frames["topFrame"]
5.frames[0]
6.frames["topFrame"]
框架集的第三个框架 也就是命名leftFrame这个
1.window.frames[1]
2.window.frames["leftFrame"]
3.top.frames[1]
4.top.frames["leftFrame"]
5.frames[1]
6.frames["leftFrame"]
框架集的第二个框架 也就是命名rightFrame这个
1.window.frames[2]
2.window.frames["rightFrame"]
3.top.frames[2]
4.top.frames["rightFrame"]
5.frames[2]
6.frames["rightFrame"]
与 top 相对的另一个 window 对象是 parent 。顾名思义, parent (父)对象始终指向当前框架的
直接上层框架。在某些情况下, parent 有可能等于 top ;但在没有框架的情况下, parent 一定等于
top (此时它们都等于 window )。再看下面的例子。
Frameset Example
另一个框架集
这个框架集中的一个框架包含了另一个框架集,该框架集的代码如下所示。
Frameset Example
浏览器在加载完第一个框架集以后,会继续将第二个框架集加载到 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 和 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 中),则取得这两个属性的值。如果不存在(在 Firefox 中),则取得 screenX
和 screenY 的值。
在使用这些值的过程中,还必须注意一些小问题。在 IE、Opera 中,screenLeft 和 screenTop 中保存
的是从屏幕左边和上边到由 window 对象表示的页面可见区域的距离。
换句话说,如果 window 对象是
最外层对象,而且浏览器窗口紧贴屏幕最上端——即 y 轴坐标为 0,那么 screenTop 的值就是位于页面
可见区域上方的浏览器工具栏的像素高度。但是,在 Chrome、Firefox和 Safari中, screenY 或 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 和 IE 7(及更高版本)中默认就
是禁用的。另外,这两个方法都不适用于框架,只能对最外层的 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 返回相同的值,即视口(viewport)大小而非浏览器窗口大小。
IE8 及更早版本没有提供取得当前浏览器窗口尺寸的属性;不过,它通过 DOM 提供了页面可见区域
的相关信息。
在 IE、Firefox、Safari、Opera 和 Chrome 中, document.documentElement.clientWidth 和
document.documentElement.clientHeight 中保存了页面视口的信息。在 IE6 中,这些属性必须在
标准模式下才有效;如果是混杂模式,就必须通过 document.body.clientWidth 和 document.body.
clientHeight 取得相同信息。而对于混杂模式下的 Chrome,则无论通过 document.documentEle-
ment 还是 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.client-
Height 的值。否则,就使用 document.body.clientWidth 和 document.body.clientHeight 的值。
对于移动设备, window.innerWidth 和 window.innerHeight 保存着可见视口,也就是屏幕上可
见页面区域的大小。移动 IE 浏览器不支持这些属性,但通过 document.documentElement.client-
Width 和 document.documentElement.clientHeihgt 提供了相同的信息。随着页面的缩放,这些值
也会相应变化。
在其他移动浏览器中, document.documentElement 度量的是布局视口,即渲染后页面的实际大
小(与可见视口不同,可见视口只是整个页面中的一小部分)。移动 IE 浏览器把布局视口的信息保存在
document.body.clientWidth 和 document.body.clientHeight 中。这些值不会随着页面缩放变化。
由于与桌面浏览器间存在这些差异,最好是先检测一下用户是否在使用移动设备,然后再决定使用
哪个属性。
另外,使用 resizeTo() 和 resizeBy() 方法可以调整浏览器窗口的大小。这两个方法都接收两个
参数,其中 resizeTo() 接收浏览器窗口的新宽度和新高度,而 resizeBy() 接收新窗口与原窗口的宽
度和高度之差。来看下面的例子。
//调整到 100×100
window.resizeTo(100, 100);
//调整到 200×150
window.resizeBy(100, 50);
//调整到 300×300
window.resizeTo(300, 300);
需要注意的是,这两个方法与移动窗口位置的方法类似,也有可能被浏览器禁用;而且,在 Opera
和 IE7(及更高版本)中默认就是禁用的。另外,这两个方法同样不适用于框架,而只能对最外层的
window 对象使用。