JS中的BOM

1. BOM

BOM(Browers Object Model)是浏览器对象模型,通过JS操作BOM来控制浏览器的各种行为。
BOM对象如下图所示。

Window对象的子对象:

  • document子对象,DOM的对象,文档对象模型
  • frames子对象,浏览器框架集合对象
  • history子对象,浏览器历史信息对象
  • location子对象,浏览器位置信息对象
  • navigator子对象,浏览器导航对象,存放浏览器的信息
  • screen子对象,浏览器屏幕对象

2. Window对象

所有浏览器都支持 window 对象。它表示浏览器窗口。
所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。全局变量是 window 对象的属性。全局函数是 window 对象的方法。HTML DOM 的 document 也是 window 对象的属性之一:

1
2
3
window.document.getElementById("btn");
// 等价于
document.getElementById("btn");

确定浏览器窗口尺寸的兼容代码:

1
2
3
4
5
6
7
8
9
// 窗口的宽
var w=window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;

// 窗口的高
var h=window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;

其它Window方法:

  • window.open() – 打开新窗口
  • window.close() – 关闭当前窗口
  • window.moveTo() – 移动当前窗口
  • window.resizeTo() – 调整当前窗口的尺寸

3. frames对象

如果页面中包含框架,则每个框架都拥有自己的window对象,并且保存在frames集合中。

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head>
<title>Document</title>
</head>
<frameset rows="160,*">
<frame src="frame.htm" name="topFrame">
<frameset>
<frame src="anotherframe.htm" name="leftFrame">
<frame src="yetanotherframe.htm" name="rightFrame">
</frameset>
</frameset>
</html>

以上代码创建了一个框架集,其中一个框架居上,两个框架局下。对于这个例子,可以通过window.frames[0]或者window.frames[“topFrame”]来引用上方的框架。不过最好使用top而非window,因为top对象始终指向最高最外层的框架。
在使用框架的情况下,浏览器会存在多个Global对象。每个window对象都包含原生类型的构造函数,因此每个框架都有一套自己的构造函数,这些构造函数一一对应,但并不相等。

4. location对象

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
pathname “/wileyCDA/“ 返回URL中的目录和文件名
port “8080” 返回URL中指定的端口号,如没有,返回空
protocol “http:” 返回页面中使用的协议
search “?q=javascript” 返回URL中的查询字符串
  1. 查询字符串参数
    上面location.search返回从问号到URL末尾的所有内容,但却没有办法访问其中的每个查询字符串参数。
    为此需要创建一个函数,用以解析查询字符串。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    function getQueryStringArgs(){
    //取得查询字符串并去掉前面的?号
    var qs = (location.search.length > 0 ? location.search.substring(1) : ""),
    args = {},
    items = qs.length ? qs.split("&") : [],
    item = null,
    name = null,
    value = null,

    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;
    }

    //假设查询字符串是?q=javascript&num=10
    var args = getQueryStringArgs();
    alert(args["q"]); // "javascript"
    alert(args["num"]); // "10"
  2. 位置操作
    location对象可以通过很多方式来改变浏览器的位置。

    1
    2
    3
    location.assign("http://www.wrox.com");
    window.location = "http://www.wrox.com";
    location.href = "http://www.wrox.com"; // 常用

另外,修改location对象的其它属性也可以改变当前加载的页面。

1
2
3
4
5
6
7
8
9
10
11
// 假设初始URL为http://www.wrox.com/WileyCDA/

location.hash = "#section1"; // http://www.wrox.com/WileyCDA/#section1

location.search = "?q=javascript"; // http://www.wrox.com/WileyCDA/?q=javascript

location.hostname = "www.yaho.com"; // http://www.yaho.com/WileyCDA/

location.pathname = "mydir"; // http://www.wrox.com/mydir/

location.port = 8080; // http://www.wrox.com:8080/WileyCDA/

当通过上述任何一种方式改变URL以后,浏览器的历史记录就会生成一条新记录,因此用户通过单击后退按钮都会导航到前一个页面。

5. navigator对象

window.navigatornavigator 对象已成为识别客户端浏览器的事实标准。但每一种浏览器的 navigator 对象都有自己的属性,下表列出了部分属性:

属性或方法 说明 IE Firefox Safari/Chrome Opera
appCodeName 浏览器名称,通常是Mozilla 3.0+ 1.0+ 1.0+ 7.0+
appMinorVersion 次版本信息 4.0+ - - 9.5+
appName 浏览器的完整名称 3.0+ 1.0+ 1.0+ 7.0+
appVersion 浏览器版本,不与实际版本对应 3.0+ 1.0+ 1.0+ 7.0+
buildID 浏览器的编译版本 - 2.0+ - -
cookieEnabled cookie 是否启用 4.0+ 1.0+ 1.0+ 7.0+
cpuClass 客户端的计算机使用的CPU类型 4.0+ - - -
  1. 检测插件
    跨浏览器检测插件的方法是针对每个插件分别创建函数,比如下面两个:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //检测所有浏览器中的 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;
    }

    alert(hasFalsh());

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

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

第一个参数是要处理的MIME类型,第二个参数是处理该MIME类型的页面的URL,第三个参数是应用程序的名称。
同样的,registerProtocolHandler()方法也接收3个参数,以下例子注册了一个mailto协议的处理程序。

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

6. screen对象

window.screen 对象包含有关用户屏幕的信息,下表列出了部分screen的属性。

属性 说明
height 屏幕的像素高度
width 屏幕的像素宽度
availHeight 屏幕的像素高度减去系统部件高度之后的值(只读)
availWidth 屏幕的像素宽度减去系统部件宽度之后的值(只读)
left 当前屏幕距左边的像素距离[firefox返回0,chrome和IE不支持]
top 当前屏幕距上方的像素距离[firefox返回0,chrome和IE不支持]
availLeft 未被系统部件占用的最左侧的像素值(只读)[chrome和firefox返回0,IE不支持]
availTop 未被系统部件占用的最上方的像素值(只读)[chrome和firefox返回0,IE不支持]

以下代码显示了部分用法:

1
2
3
4
5
6
<script>
console.log(screen.availHeight); // 1040
console.log(screen.availWidth); // 1920
console.log(screen.width); // 1920
console.log(screen.height); // 1080
</script>

7. history对象

window.history 对象包含用户上网的历史记录。

1
2
3
4
5
6
history.go(-1); // 后退一页
history.go(1); // 前进一页
history.go(2); // 前进两页

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

history对象还有一个length属性,保存着历史记录数量,对于加载的第一个页面而言,history.length等于0;

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

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

参考书籍:《JavaScript高级程序设计》,作者:【美】 Nicholas C.Zakas