第8章 BOM

84 阅读9分钟

ECMAScriptt是 JavaScript 的核心,但如果要在Web 中使用 JavaScript,那么 BOM则无疑才是真正的核心。 BOM 提供了很多对象,用于访问浏览器的功能,这些功能与任何网页内容无关。W3C 为了把浏览器中 JavaScript 最基本的部分标准化,已经将 BOM 的主要方面纳入了 HTML5 的规范中。

8.1 window 对象

BOM 的核心对象是 window,它表示浏览器的一个实例。在浏览器中,window 对象有双重角色,它既是通过 JavaScript 访问浏览器窗口的一个接口,又是 ECMAScript 规定的 Global 对象。

8.1.1 全局作用域

在全局作用域中声明的变量、函数都会变成 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

事实上声明的全局作用域中的变量,当添加到window 对象的属性时,该属性的[[Configurable]] 为false,所以我们用delete去删除时没有效果。

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

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

8.1.2 窗口关系及框架

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

<html>
    <head>
        <title>Frameset Example</title>
    </head>

    <frameset rows="160,*">
        <frame src="frame.htm" name="topFrame">
        <frameset cols="50%,50%">
            <frame src="anotherframe.htm" name="leftFrame">
            <frame src="yetanotherframe.htm" name="rightFrame">
        </frameset>
    </frameset>

</html>

对这个例子而言,可以通过window.frames[0]或者 window.frames["topFrame"]来引用上方的框架。不过,恐怕你最好使用top 而非 window 来引用这些框架(例如,通过 top.frames[0])。

top对象

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

parent对象

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

self对象

与框架有关的最后一个对象是 self,它始终指向 window;实际上,self 和 window 对象可以互换使用。

8.1.3 窗口位置

用来确定和修改 window 对象位置的属性和方法有很多。

IE、Safari、Opera 和 Chrome 都提供了screenLeftscreenTop 属性,分别用于表示窗口相对于屏幕左边和上边的位置。

Firefox 则在screenXscreenY 属性中提供相同的窗口位置信息,Safari 和 Chrome 也同时支持这两个属性。

兼容性处理:

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

moveTo()和moveBy()方法

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

8.1.4 窗口大小

innerWidth和innerHeight

这两个属性是用 CSS 像素单位表示的浏览器窗口的视口宽度,包括垂直滚动条。

outerWidth 和 outerHeight

包括了浏览器外边框的窗口宽度。

Element.clientWidth和Element.clientHeight

指一个文档使用 CSS pixels 单位表示的内部宽度,包括其 padding(不包括 border、margin 或垂直滚动条)。这就是视口的宽度

resizeTo()和 resizeBy()

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

8.1.5 导航和打开窗口

window.open()方法

该方法既可以导航到一个特定的 URL,也可以打开一个新的浏览器窗口

  • 可接受3个参数

    • strUrl 新窗口需要载入的 url 地址。strUrl可以是 web 上的 html 页面也可以是图片文件或者其他任何浏览器支持的文件格式。或者是特殊窗口名称:_self、_parent、_top 或_blank。
    • strWindowName 新窗口的名称。该字符串可以用来作为超链接 <a> 或表单 <form> 元素的目标属性值。字符串中不能含有空白字符。注意:strWindowName 并不是新窗口的标题。
    • strWindowFeatures可选参数。是一个字符串值,这个值列出了将要打开的窗口的一些特性 (窗口功能和工具栏) 。字符串中不能包含任何空白字符,特性之间用逗号分隔开。
  • 返回一个指向新窗口的引用

8.1.6 循环定时器和定时器

setTimeout()

第一个参数

可以是一个包含JavaScript 代码的字符串,也可以是一个函数。传递字符串可能导致性能损失。

//不建议传递字符串!
setTimeout("alert('Hello world!') ", 1000);

//推荐的调用方式
setTimeout(function() {
    alert("Hello world!");
}, 1000);
第二个参数

是一个表示等待多长时间的毫秒数,其实际意义是再过多长时间把当前任务添加到任务队列中。

返回值

setTimeout()之后,该方法会返回一个数值 ID,表示当前设置的超时定期的ID。

clearTimeout()

该方法用于取消超时定时器,接受一个参数,参数为设置的超时定时器返回的ID。

setInterval()

它接受的参数与 setTimeout()相同。同样也返回一个循环定时器的ID

clearInterval()

该方法用于取消循环定时器,接受一个参数,参数为设置的循环定时器返回的ID。

8.1.7 系统对话框

浏览器通过 alert()、confirm()和 prompt()方法可以调用系统对话框向用户显示消息。系统对 话框与在浏览器中显示的网页没有关系,也不包含 HTML。

8.2 location 对象

location 是最有用的 BOM 对象之一,它提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功能。 它既是window对象的属性,也是document对象的属性。

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

属性名例子说明
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的查询字符串。这个字符串以问号开头

8.2.1 位置操作

使用assign()方法并为其传递一个 URL,来改变浏览器的位置。如果由于安全原因无法执行跳转,那么会抛出一个 SECURITY_ERROR 类型的 DOMException。当调用此方法的脚本来源和页面的 Location 对象中定义的来源隶属于不同域的时候,就会抛出上述错误。

location.assign("http://www.wrox.com");

这样,就可以立即打开新 URL 并在浏览器的历史记录中生成一条记录。如果是将 location.href 或 window.location 设置为一个 URL 值,也会以该值调用 assign()方法。

window.location = "http://www.wrox.com";
location.href = "http://www.wrox.com";

另外,修改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 来替换当前的资源。当前的资源被替换后不会在浏览器的历史记录中。

reload()

它的作用是重新加载当前显示的页面。如果不传递任何参数,页面就会以最有效的方式重新加载,也就是说有可能从缓存中重新加载。

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

8.3  navigator 对象

navigator 对象却是所有支持 JavaScript 的浏览器所共有的。与其他 BOM 对象的情况一样,每个浏览器中的 navigator 对象也都有一套自己的属性。它是只读的。

8.3.1 检测插件

对于非 IE 浏览器,可以使用plugins 数组来达到这个目的。该数组中的每一项都包含下列属性。

  • name:插件的名字。
  • description:插件的描述。
  • filename:插件的文件名。
  • length:插件所处理的 MIME 类型数量。
//检测插件(在 IE 中无效)

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"));

8.3.2 注册处理程序

registerContentHandler()和 registerProtocolHandler()方法可以让一个站点指明它可以处理特定类型的信息。前者可以要将一个站点注册为处理RSS 源的处理程序,后者可以注册一个mailto 协议的处理程序。

8.4 screen 对象

screen 对象基本上只用来表明客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素宽度和高度等。具体在编程当中用处不大。

8.5 history 对象

history 对象保存着用户上网的历史记录,从窗口被打开的那一刻算起。history 是 window对象的属性。

因此每个浏览器窗口每个标签页乃至每个框架,都有自己的 history 对象与特定的window 对象关联。

go()方法

可以在用户的历史记录中任意跳转,可以向后也可以向前。

  • 接受一个参数,
  • 当接受的是一个整数值时,负数表示向后跳转,正数表示向前跳转
  • 当接受的是一个个字符串参数,浏览器会跳转到历史记录中包含该字符串的第一个位置———可能后退,也可能前进
//后退一页
history.go(-1);
//前进一页
history.go(1);
//前进两页
history.go(2);
//跳转到最近的 wrox.com 页面
history.go("wrox.com");
//跳转到最近的 nczonline.net 页面
history.go("nczonline.net");

back() 和 forward()

顾名思义,这两个方法可以模仿浏览器的“后退”和“前进”按钮。

//后退一页
history.back();

//前进一页
history.forward();