BOM(浏览器对象模型),提供了很多对象,用于访问浏览器的功能,这些功能与任何网页内容无关。
window对象
BOM的核心对象是window。它表示浏览器的一个实例。
在浏览器中,window对象有双重角色:既是通过JavaScript访问浏览器窗口的一个接口,又是ECMAScript规定的Global对象。
全局作用域
所有在全局作用域中声明的变量、函数都会变成window对象的属性和方法。
eg:
var age = 29;
function sayAge(){
alert(this.age);
}
alert(window.age); //29
sayAge(); //29window.sayAge(); //29
定义全局变量与在window对象上直接定义属性的区别在于:全局变量不能通过delete操作符删除,而直接在window对象上定义的属性可以。
eg:
var age = 29;
window.color = "red";
//在IE<9时抛出错误,在其他所有浏览器中都返回falsedelete window.age;
//在IE<9时抛出错误,在其他所有浏览器中都返回truedelete window.color; //returns true
alert(window.age); //29
alert(window.color); //undefined
尝试访问未声明的变量会抛出错误,但是通过查询window对象,可以知道某个未声明的变量是否存在。
//这里会抛出错误,因为oldValue未定义var newValue = oldValue;
//这里不会抛出错误,因为这是一次属性查询//newValue的值是undefinedvar newValue = window.oldValue;
窗口关系及框架
如果页面中包含框架,则每个框架都拥有自己的window对象,并保存在frames集合中。
在frames集合中,可以通过数值索引(从0开始,从左至右,从上到下)或者框架名称来访问相应的window对象。
每个window对象都有一个name属性,其中包含框架的名称。
<!DOCTYPE html><html lang="en"><head>
<meta charset="UTF-8" />
<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对象始终指向最高(最外)层的框架,也就是浏览器窗口。所以,最好使用top.frames[0]来访问上方框架。
与top相对的另一个window对象是parent,parent(父)对象始终指向当前框架的直接上层框架。在没有框架的情况下,parent一定等于top(此时它们都等于window)。
除非最高层窗口是通过window.open()打开的,否则其window对象的name属性不会包含任何值。
与框架有关的最后一个对象是self,它始终指向window,实际上,self和window对象可以互换使用。
所有这些对象(top、parent、self)都是window对象的属性,可以通过window.parent、window.top等形式来访问。
可以将不同层次的window对象连缀起来,如:window.parent.parent.frames[0]。
在使用框架的情况下,浏览器中会存在多个Global对象。在每个框架中定义的全局变量会自动成为框架中window对象的属性。由于每个window对象都包含原生类型的构造函数,因为每个框架都有一套自己的构造函数,这些构造函数一一对应,但并不相等。如:top.Object并不等于top.frames[0].Object。这个问题会影响到对跨域框架传递的对象使用instanceof操作符。
窗口位置
screenLeft和screenTop属性,分别用于标识窗口相对于屏幕左边和上边的位置。(Firefox则在screenX和screenY属性中提供相同的窗口位置信息,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()接收的是新位置的x和y坐标值,moveBy()接收的是在水平和垂直方向上移动的像素数。
//将窗口移动到屏幕左上角window.moveTo(0, 0);
//将窗口向下移动100像素window.moveBy(0, 100);
//将窗口移动到(200,300)window.moveTo(200, 300);
//将窗口向左移动50像素window.moveBy(-50,0);
这两个方法可能会被浏览器禁用;而且,在Opera和IE7(及更高版本)中默认就是禁用的。
这两个方法都不适用于框架,只能对最外层的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及更早版本没有提供取得当前浏览器窗口尺寸的属性。
取得页面视口大小的代码如下:
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;
}
}
使用resizeTo()和resizeBy()方法可以调整浏览器窗口的大小。这两个方法都接收两个参数,其中resizeTo()接收浏览器窗口的新宽度和新高度,而resizeBy()接收新窗口与原窗口的宽度和高祖只差。
这两个方法与移动窗口位置的方法类似,也可能被浏览器禁用;在Opera和IE7(及更高版本中)默认就是禁用的。这两个方法同样不适用于框架,只能对最外层的window对象使用。
导航和打开窗口
使用window.open()方法即可以导航到一个特定的URL,也可以打开一个新的浏览器窗口。
这个方法接收4个参数:要加载的URL、窗口目标、一个特性字符串、一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值。
如果传递了第二个参数,而且该参数是已有窗口或框架的名称,那么就会在具有该名称的窗口或框架中加载第一个参数指定的URL。
第二个参数可以是下列特殊的窗口名称:_self、_parent、_top或_blank。
- 弹出窗口
如果给window.open()传递的第二个参数并不是一个已经存在的窗口或框架,那么该方法就会根据在第三个参数位置上传入的字符串创建一个新窗口或新标签页。如果没有传入第三个参数,就会打开一个带有全部默认设置(工具栏、地址栏和状态栏)的新浏览器窗口。在不打开新窗口的情况下,会忽略第三个参数。
第三个参数是一个用逗号分隔的设置字符串,表示在新窗口中有显示那些特性。
设 置 | 值 | 说明 |
---|---|---|
fullscreen | yes或no | 表示浏览器窗口是否最大化。仅限IE |
height | 数值 | 表示新窗口的高度。不能小于100 |
left | 数值 | 表示新窗口的左坐标。不能是负值 |
location | yes或no | 表示是否在浏览器窗口中显示地址栏。不同浏览器的默认值不同。如果设置为no,地址栏可能会隐藏,也可能会被禁用(取决于浏览器) |
menubar | yes或no | 表示是否在浏览器窗口中显示菜单栏。默认值为no |
resizable | yes或no | 表示是否可以通过拖动浏览器窗口的边框改变其大小。默认值为no |
scrollbars | yes或no | 表示如果内容在视口中显示不下,是否允许滚动。默认值为no |
status | yes或no | 表示是否在浏览器窗口中显示状态栏。默认值为no |
toolbar | yes或no | 表示是否在浏览器窗口中显示工具栏。默认值为no |
top | 数值 | 表示新窗口的上坐标。不能是负值 |
width | 数值 | 表示新窗口的宽度。不能小于100 |
表中所列的部分或全部设置选项,都可以通过逗号分隔的名值对列表来指定。
eg:
window.open("http://www.wrox.com/","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");
window.open()方法会返回一个指向新窗口的引用。
调用window.close()方法可以关闭新打开的窗口。这个方法仅适用于通过window.open()打开的弹出窗口。
新创建的window对象有一个opener属性,其中保存着打开它的原始窗口对象。这个属性只在弹出窗口中的最外层window对象(top)中有定义,而且指向调用window.open()的窗口或框架。
eg:
var wroxWin = window.open("http://www.wrox.com/","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");
alert(wroxWin.opener == window); //true
-
安全限制
各种浏览器对弹出窗口都有不同的限制。 -
弹出窗口屏蔽程序
如果浏览器内置的屏蔽程序阻止的弹出窗口,那么window.open()很可能会返回null。
检测弹出窗口是否被屏蔽的代码如下:
var wroxWin = window.open("http://www.wrox.com/","_blank");
if (worxWin == null) {
alert("The popup was blocked!");
}
如果是浏览器扩展或其他程序阻止的弹出矿口,那么window.open()通常会抛出一个错误。
以下是准确的检测弹出窗口是否被屏蔽的代码:
var blocked = false;
try{
var wroxWin = window.open("http://www.wrox.com", "_blank");
if (worxWin == null) {
blocked = true;
}
} catch (ex) {
blocked = true;
}
if (blocked) {
alert("The popup was blocked!");
}
间歇调用和超时调用
javaScript是单线程语言,但它允许通过设置超时值和间歇时间值来调度代码在特定的时刻执行。
超时调用使用window.setTimeout()方法,接收两个参数:要执行的代码和以毫秒表示的时间。
eg:
//不建议传递字符串!//setTimeout("alert('Hello world!')", 1000);
//推荐的调用方式
setTimeout(function(){
alert("Hello world!");
}, 1000);
传递字符串可能导致性能损失,因此不建议以字符串作为第一个参数。
第二个参数是一个表示等待多长时间的毫秒数,但经过该时间后制定的代码不一定会执行。因为JavaScript是一个单线程的解释器,因此一定时间内只能执行一段代码。为了控制要执行的代码,就有一个JavaScript任务队列。这些任务会按照将它们添加到队列的顺序执行。setTimeout()的第二个参数告诉JavaScript何时将任务添加到队列中。如果队列是空的,那么添加的代码会立即执行;如果队列不是空的,那么就要等前面的代码执行完了以后再执行。
setTimeout()方法会返回一个数值ID,表示超时调用,可以通过它来取消超时调用。
要取消尚未执行的超时调用计划,可以调用clearTimeout()方法,并将相应的超时调用ID作为参数传递给它。
eg:
//设置超时调用var timeoutId = setTimeout(function(){
alert("Hello world!");
}, 1000);
//注意:把它取消
clearTimeout(timeoutId);
超时调用的代码都是在全局作用域中执行的,因此函数中this的值在非严格模式下指向window对象,在严格模式下是undefined。
设置间歇调用的方法是setInterval(),它接受的参数与setTimeout()相同:要执行的代码和以毫秒表示的时间。
setTimeout()同样返回一个间歇调用ID,可以用于在某个时刻使用clearInterval()取消间歇调用。
eg:
var num = 0;
var max = 10;
var intervalId = null;
function incrementNumber() {
num++;
//如果执行次数达到了max设定的值,则取消后续尚未执行的调用
if(num == max){
clearInterval(intervalId);
alert("Done");
}
}
intervalId = setInterval(incrementNumber, 500);
可以使用超时调用来改写以上例子
var num = 0;
var max = 10;
function incrementNumber() {
num++;
//如果执行次数达到了max设定的值,则取消后续尚未执行的调用
if(num < max){
setTimeout(incrementNumber, 500);
} else {
alert("done");
}
}
setTimeout(incrementNumber, 500);
在开发环境下,很少使用真正的间歇调用,因为后一个间歇调用可能会在前一个间歇调用结束之前启动。使用超时调用完全可以避免这一点。所以,最好不要使用间歇调用。
系统对话框
通过alert()、confirm()和prompt()方法可以调用系统对话框向用户显示消息。
系统对话框与在浏览器中显示的网页没有关系,也不包含HTML。它们的外观由操作系统及(或)浏览器设置决定,而不是由CSS决定。
alert()方法接受一个字符串并将其显示给用户。通常使用alert()生成的“警告”对话框向用户显示一些他们无法控制的信息,例如错误消息。
confirm()方法与alert()方法不同之处在于多了一个取消按钮。该方法返回一个布尔值:true表示单击了OK,false表示单击了cancel或者单击了右上角的X按钮。
典型用法:
if (confirm("Are you sure?")) {
alert("I`m so glad you're sure!");
} else {
alert("I`m sorry to hear you're not sure.");
}
prompt()方法生成一个“提示”框,用于提示用户输入一些文本。提示框中除了显示OK和Cancel按钮外,还会显示一个文本输入域,以供用户在其中输入内容。该方法接受两个参数:要显示给用户的文本提示和文本输入域的默认值(可以是一个空字符串)。如果用户单击了OK,该方法返回文本输入域的值。如果用户单击了Cancel或通过其他方式关闭了对话框,则返回null。
eg:
var result = prompt("what is you name?", "");
if (result !== null) {
alert("Welcome, " + result);
}
window.find()可以打开查找对话框
window.print()可以打开打印对话框
这两个对话框都是异步显示的,能够将控制权立即交还给脚本。
location对象
location对象提供了当前窗口中加载的文档有关的信息,还提供了一些导航功能。
location即是window对象的属性也是document对象的属性。window.location和document.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的查询字符串。这个字符串以问号开头 |
查询字符串参数
location.search返回从问号到URL末尾的所有内容。
解析查询字符串的例程:
function getQueryStringArgs() {
//取得查询字符串并去掉开头的问号
var qs = (location.search.length > 0 ? location.search.substring(1) : "");
//保存数据的对象
args = {};
//取得每一项
items = qs.length ? qs.split("&") : [];
itme = null;
name = null;
value = null;
//在for循环中使用
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;
}
位置操作
location.assign()方法可以立即打开新URL并在浏览器的历史记录中生成一条记录。
为location.href或window.location设置一个URL值,也会调用assign()方法。
eg:
//假设初始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()方法不会在历史记录中生成新记录,因此调用此方法后用户不能回到前一个页面。
reload()的作用是重新加载当前显示的页面,不传递参数时,页面会以最有效的方式重新加载。也就是说如果页面自上次请求以来并没有改变过,页面就会从浏览器缓存中重新加载。如果要强制从服务器从新加载,需要为该方法传递参数true。
navigator对象
检测插件
对于非IE浏览器,可以使用plugins数组来检测浏览器是否安装了特定插件。该数组中的每项都包含下列属性:
- name: 插件的名字
- description: 插件的描述
- filename: 插件的文件名
- length: 插件所处理的MIME类型数量
eg:
//检测插件(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"));
在IE中检测插件的唯一方式就是使用专有的ActiveXObject类型,并尝试创建一个特定插件的实例。IE是以COM对象的方式实现插件的,而COM对象使用唯一标识符来标识。
eg:
//检测IE中的插件function hasIEPlugin(name) {
try {
new ActiveXObject(name);
return true;
} catch (ex) {
return false;
}
}
//检测Flash
alert(hasIEPlugin("ShockwaveFlash.ShockwaveFlash"));
//检测QuickTime
alert(hasIEPlugin("QuickTime.QuickTime"));
注册处理程序
Firefox2为navigator对象新增了registerContentHandler()和registerProtocolHandler()方法(这两个方法是在HTML5中定义的)。这两个方法可以让一个站点指明它可以处理特定类型的信息。
registerContentHandler()方法接收三个参数:要处理的MIME类型、可以处理该MIME类型的页面的URL以及应用程序名称。
eg:将一个站点注册为处理RSS源的处理程序
navigator.registerContentHandler("application/rss+xml","http://www.somereader.com?feed=%s", "Some Reader");
eg:注册mailto协议的处理程序
navigator.registerProtocolHandler("mailto", "http://www.somemailclient.com?cmd=%s", "Some Mail Client");
screen对象
每个浏览器中的screen对象都包含着各不相同的属性:
history对象
history对象保存着用户上网的历史记录,从窗口被打开的那一刻算起。
history是window对象的属性,因此每个浏览器窗口、每个标签乃至每个框架,都有自己的history对象与特定的window对象关联。
使用go()方法可以在用户的历史记录中任意跳转,该方法接受一个参数,表示向后或向前跳转的页面数的一个整数值。负数表示向后跳转(后退),整数表示向前跳转(前进)。
也可以给go()方法传递一个字符串参数,此时浏览器会跳转到历史记录中包含该字符串的第一个位置,如果历史记录不包含该字符串,那么这个方法什么也不做。
可以使用back()和forward()来代替go()。
history的length属性,保存历史记录的数量。