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的查询字符串。这个字符串以问号开头 |
1.查询字符串参数
虽然通过上面的属性可以访问到 location
对象的大多数信息,但其中访问 URL 包含的查询字符串的属性并不方便。尽管 location.search
返回从问号到 URL 末尾的所有内容,但却没有办法逐个访问其中的每个查询字符串参数。为此,可以像下面这样创建一个函数,用以解析查询字符串,然后返回包含所有参数的一个对象:
1 | function getQueryStringArgs () { |
这个函数的第一步是先去掉查询字符串开头的问号。当然,前提是 location.search
中必须要包含一或多个字符。然后,所有参数将被保存在 args
对象中,该对象以字面量形式创建。接下来,根据和号(&
)来分割查询字符串,并返回 name=value
格式的字符串数组。下面的 for 循环会迭代这个数组,然后再根据等于号分割每一项,从而返回第一项为参数名,第二项为参数值的数组。再使用 decodeURIComponent()
分别解码 name
和 value
(因为查询字符串应该是被编码过的)。最后,将 name
作为 args
对象的属性,将 value
作为相应属性的值。下面给出了使用这个函数的示例。
1 | // 假设查询字符串是 ?q=javascript&num=10 |
可见,每个查询字符串参数都成了返回对象的属性。这样就极大地方便了对每个参数的访问。
2.位置操作
使用 location
对象可以通过很多方式来改变浏览器的位置。首先,也是最常用的方式,就是使用 assign()
方法并为其传递一个 URL,如下所示。
1 | location.assign("http://www.wrox.com"); |
这样,就可以立即打开新 URL 并在浏览器的历史记录中生成一条记录。如果是将 location.href
或 window.location
设置为一个 URL 值,也会以该值调用 assign()
方法。例如,下列两行代码与显式调用 assign()
方法的效果完全一样。
1 | window.location = "http://www.wrox.com"; |
在这些改变浏览器位置的方法中,最常用的是设置 location.href
属性。
另外,修改 location
对象的其他属性也可以改变当前加载的页面。下面的例子展示了通过将 hash
、search
、hostname
、pathname
和 port
属性设置为新值来改变 URL。
1 | // 假设初始 URL 为 http://www.wrox.com/WileyCDA/ |
每次修改 location
的属性(hash
除外),页面都会以新 URL 重新加载。
当通过上述任何一种方式修改 URL 之后,浏览器的历史记录中就会生成一条新记录,因此用户通过单击“后退”按钮都会导航到前一个页面。要禁用这种行为,可以使用 replace()
方法。这个方法只接受一个参数,即要导航到的 URL;结果虽然会导致浏览器位置改变,但不会在历史记录中生成新记录。在调用 replace()
方法之后,用户不能回到前一个页面,来看下面的例子:
1 |
|
如果将这个页面加载到浏览器中,浏览器就会在 1 秒钟后重新定向到 www.wrox.com
。然后,“后退”按钮将处于禁用状态,如果不重新输入完整的 URL,则无法返回示例页面。
与位置有关的最后一个方法是 reload()
,作用是重新加载当前显示的页面。如果调用 reload()
时不传递任何参数,页面就会以最有效的方式重新加载。也就是说,如果页面自上次请求以来并没有改变过,页面就会从浏览器缓存中重新加载。如果要强制从服务器重新加载,则需要像下面这样为该方法传递参数 true
。
1 | location.reload(); // 重新加载(有可能从缓存中加载) |
3.navigator 对象
最早由 Netscape Navigator 2.0 引入的 navigator
对象,现在已经成为识别客户端浏览器的事实标准。虽然其他浏览器也通过其他方式提供了相同或相似的信息(例如,IE 中的 window.clientInformation
和 Opera 中的 window.opera
),但 navigator
对象却是所有支持 JavaScript 的浏览器所共有的。与其他 BOM 对象的情况一样,每个浏览器中的 navigator
对象也都有一套自己的属性。下表列出了存在于所有浏览器中的属性和方法,以及支持它们的浏览器版本。
属性或方法 | 说明 | IE | Firefox | Safari/Chrome | Opera |
---|---|---|---|---|---|
appCodeName | 浏览器的名称。通常都是Mozilla,即使在非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类型(x86、68K、Alpha、PPC或Other) | 4.0+ | - | - | - |
javaEnabled() | 表示当前浏览器中是否启用了Java | 4.0+ | 1.0+ | 1.0+ | 7.0+ |
language | 浏览器的主语言 | - | 1.0+ | 1.0+ | 7.0+ |
mimeTypes | 在浏览器中注册的MIME类型数组 | 4.0+ | 1.0+ | 1.0+ | 7.0+ |
onLine | 表示浏览器是否连接到了因特网 | 4.0+ | 1.0+ | - | 9.5+ |
opsProfile | 似乎早就不用了。查不到相关文档 | 4.0+ | - | - | - |
oscpu | 客户端计算机的操作系统或使用的CPU | - | 1.0+ | - | - |
platform | 浏览器所在的系统平台 | 4.0+ | 1.0+ | 1.0+ | 7.0+ |
plugins | 浏览器中安装的插件信息的数组 | 4.0+ | 1.0+ | 1.0+ | 7.0+ |
preference() | 设置用户的首选项 | - | 1.5+ | - | - |
product | 产品名称(如 Gecko) | - | 1.0+ | 1.0+ | - |
productSub | 关于产品的次要信息(如Gecko的版本) | - | 1.0+ | 1.0+ | - |
registerContentHandler() | 针对特定的MIME类型将一个站点注册为处理程序 | - | 2.0+ | - | - |
registerProtocolHandler() | 针对特定的协议将一个站点注册为处理程序 | - | 2.0 | - | - |
securityPolicy | 已经废弃。安全策略的名称。为了与Netscape Navigator 4向后兼容而保留下来 | - | 1.0+ | - | - |
systemLanguage | 操作系统的语言 | 4.0+ | - | - | - |
taintEnabled() | 已经废弃。表示是否允许变量被修改(taint)。为了与Netscape Navigator 3向后兼容而保留下来 | 4.0+ | 1.0+ | - | 7.0+ |
userAgent | 浏览器的用户代理字符串 | 3.0+ | 1.0+ | 1.0+ | 7.0+ |
userLanguage | 操作系统的默认语言 | 4.0+ | - | - | 7.0+ |
userProfile | 借以访问用户个人信息的对象 | 4.0+ | - | - | - |
vendor | 浏览器的品牌 | - | 1.0+ | 1.0+ | - |
vendorSub | 有关供应商的次要信息 | - | 1.0+ | 1.0+ | - |
表中的这些 navigator 对象的属性通常用于检测显示网页的浏览器类型。
3.1 检测插件
检测浏览器中是否安装了特定的插件是一种最常见的检测例程。对于非 IE 浏览器,可以使用 plugins
数组来达到这个目的。该数组中的每一项都包含下列属性。
- name:插件的名字。
- description:插件的描述。
- filename:插件的文件名。
- length:插件所处理的 MIME 类型数量。
一般来说,name
属性中会包含检测插件必需的所有信息,但有时候也不完全如此。在检测插件时,需要像下面这样循环迭代每个插件并将插件的 name
与给定的名字进行比较。
1 | // 检测插件(在 IE 中无效) |
这个 hasPlugin()
函数接受一个参数:要检测的插件名。第一步是将传入的名称转换为小写形式,以便于比较。然后,迭代 plugins
数组,通过 indexOf()
检测每个 name
属性,以确定传入的名称是否出现在字符串的某个地方。比较的字符串都使用小写形式可以避免因大小写不一致导致的错误。而传入的参数应该尽可能具体,以避免混淆。应该说,像 Flash
和 QuickTime
这样的字符串就比较具体了,不容易导致混淆。在 Firefox、Safari、Opera 和 Chrome 中可以使用这种方法来检测插件。
检测 IE 中的插件比较麻烦,因为 IE 不支持 Netscape
式的插件。在 IE 中检测插件的唯一方式就是使用专有的 ActiveXObject
类型,并尝试创建一个特定插件的实例。IE 是以 COM 对象的方式实现插件的,而 COM 对象使用唯一标识符来标识。因此,要想检查特定的插件,就必须知道其 COM 标识符。例如,Flash 的标识符是 ShockwaveFlash.ShockwaveFlash
。知道唯一标识符之后,就可以编写类似下面的函数来检测 IE 中是否安装相应插件了。
1 | //检测 IE 中的插件 |
在这个例子中,函数 hasIEPlugin()
只接收一个 COM 标识符作为参数。在函数内部,首先会尝试创建一个 COM 对象的实例。之所以要在 try-catch
语句中进行实例化,是因为创建未知 COM 对象会导致抛出错误。这样,如果实例化成功,则函数返回 true
;否则,如果抛出了错误,则执行 catch
块,结果就会返回 false
。例子最后检测 IE 中是否安装了 Flash 和 QuickTime 插件。鉴于检测这两种插件的方法差别太大,因此典型的做法是针对每个插件分别创建检测函数,而不是使用前面介绍的通用检测方法。来看下面的例子。
1 | // 检测所有浏览器中的 Flash |
上面代码中定义了两个函数:hasFlash()
和 hasQuickTime()
。每个函数都是先尝试使用不针对 IE 的插件检测方法。如果返回了 false
(在 IE 中会这样),那么再使用针对 IE 的插件检测方法。如果 IE 的插件检测方法再返回 false
,则整个方法也将返回 false
。只要任何一次检测返回 true
,整个方法都会返回 true
。
plugins 集合有一个名叫 refresh() 的方法,用于刷新 plugins 以反映最新安装的插件。这个方法接收一个参数:表示是否应该重新加载页面的一个布尔值。如果将这个值设置为 true,则会重新加载包含插件的所有页面;否则,只更新 plugins集合,不重新加载页面。
3.2 注册处理程序
Firefox 2为 navigator
对象新增了 registerContentHandler()
和 registerProtocolHandler()
方法(这两个方法是在 HTML5 中定义的)。这两个方法可以让一个站点指明它可以处理特定类型的信息。随着 RSS 阅读器和在线电子邮件程序的兴起,注册处理程序就为像使用桌面应用程序一样默认使用这些在线应用程序提供了一种方式。
其中,registerContentHandler()
方法接收三个参数:要处理的 MIME 类型、可以处理该 MIME 类型的页面的 URL 以及应用程序的名称。举个例子,要将一个站点注册为处理 RSS 源的处理程序,可以使用如下代码。
1 | navigator.registerContentHandler("application/rss+xml", "http://www.somereader.com?feed=%s", "Some Reader"); |
第一个参数是 RSS 源的 MIME 类型。第二个参数是应该接收 RSS 源 URL 的 URL,其中的 %s
表示RSS 源 URL,由浏览器自动插入。当下一次请求 RSS 源时,浏览器就会打开指定的 URL,而相应的Web 应用程序将以适当方式来处理该请求。
类似的调用方式也适用于 registerProtocolHandler()
方法,它也接收三个参数:要处理的协议(例如,mailto 或 ftp)、处理该协议的页面的 URL 和应用程序的名称。例如,要想将一个应用程序注册为默认的邮件客户端,可以使用如下代码。
1 | navigator.registerProtocolHandler("mailto", "http://www.somemailclient.com?cmd=%s", "Some Mail Client"); |
这个例子注册了一个 mailto 协议的处理程序,该程序指向一个基于 Web 的电子邮件客户端。同样,第二个参数仍然是处理相应请求的 URL,而 %s
则表示原始的请求。
4.screen 对象
JavaScript 中有几个对象在编程中用处不大,而 screen
对象就是其中之一。screen
对象基本上只用来表明客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素宽度和高度等。每个浏览器的 screen
对象都包含着各不相同的属性,下表列出了所有属性及支持相应属性的浏览器。
属性 | 说明 | IE | Firefox | Safari/Chrome |
---|---|---|---|---|
availHeight | 屏幕的像素高度减系统部件高度之后的值(只读) | yes | yes | yes |
availLeft | 未被系统部件占用的最左侧的像素值(只读) | yes | yes | |
availTop | 未被系统部件占用的最上方的像素值(只读) | yes | yes | |
availWidth | 屏幕的像素宽度减系统部件宽度之后的值(只读) | yes | yes | yes |
bufferDepth | 读、写用于呈现屏外位图的位数 | yes | ||
colorDepth | 用于表现颜色的位数;多数系统都是32(只读) | yes | yes | yes |
deviceXDPI | 屏幕实际的水平DPI(只读) | yes | ||
deviceYDPI | 屏幕实际的垂直DPI(只读) | yes | ||
fontSmoothingEnabled | 表示是否启用了字体平滑(只读) | yes | ||
height | 屏幕的像素高度 | yes | yes | yes |
left | 当前屏幕距左边的像素距离 | yes | ||
logicalXDPI | 屏幕逻辑的水平DPI(只读) | yes | ||
logicalYDPI | 屏幕逻辑的垂直DPI(只读) | yes | ||
pixelDepth | 屏幕的位深(只读) | yes | yes | |
top | 当前屏幕距上边的像素距离 | yes | ||
updateInterval | 读、写以毫秒表示的屏幕刷新时间间隔 | yes | ||
width | 屏幕的像素宽度 | yes | yes | yes |
这些信息经常集中出现在测定客户端能力的站点跟踪工具中,但通常不会用于影响功能。不过,有时候也可能会用到其中的信息来调整浏览器窗口大小,使其占据屏幕的可用空间,例如:
1 | window.resizeTo(screen.availWidth, screen.availHeight); |
前面曾经提到过,许多浏览器都会禁用调整浏览器窗口大小的能力,因此上面这行代码不一定在所有环境下都有效。
涉及移动设备的屏幕大小时,情况有点不一样。运行 iOS 的设备始终会像是把设备竖着拿在手里一样,因此返回的值是 768×1024。而 Android 设备则会相应调用 screen.width
和 screen.height
的值。