浏览器对象模型 (BOM)
window对象
BOM的核心对象是window,表示浏览器的一个实例。
在浏览器中,window对象有双重角色:
- 通过js访问浏览器窗口的接口
- 是ECMAScript规定的Global对象,这意味着在网页中定义的任何一个对象、变量和函数,都以window作为其Global对象
全局作用域
由于window对象同时扮演着ECMAScript中Global的角色,因此所有在全局作用域中声明的变量、函数都会变成windows对象的属性和方法。
var age = 29;
function sayAge(){
alert(this.name);
}
window.age; //29
sayAge(); //29
window.sayAge(); //29
在全局作用域中定义的变量age和函数sayAge(),被自动归在了window对象名下。于是,可以通过window.age和window.sayAge()访问变量age和函数sayAge()。
虽然全局变量会成为window的属性,但定义全局变量与在window对象上直接定义属性还是有一点差别:全局变量不能通过delete操作符删除,而直接在window对象上定义的属性可以。
var age =29;
window.color = "red";
delete window.age; //返回false
delete window.color; //返回true
window.age; //29
window.color; //undefined
因为用var语句添加的window属性有一个configurable特性,这个特性的值被设为false,因此这样定义的属性不可以通过delete操作符删除。
**在IE8及更早版本中,**使用delete删除window属性时都会报错,不管该属性最初是如何创建的。
尝试访问未声明的变量会抛出错误,但是通过查询window对象,可以知道某个可能未声明的变量是否存在:
var newValue = oldValue; //抛出错误,因为oldValue未定义
var newValue = window.oldValue; //不会抛出错误,因为这是一次属性查询
//newValue的值为undefined
后面要讨论的许多全局js对象(如location和navigator),实际上都是window对象的属性。
窗口关系及框架
如果页面中有框架,则每个框架都有自己的window对象,并且保存在frames属性中。在frames集合中,可以通过数值索引(从0开始,从左到右,从上到下)或者框架名称来访问相应的window对象。
每个window对象都有一个name属性,其中包含框架的名称。
一些名词的解释:
- screen:屏幕。这一类取到的是关于屏幕的宽度和距离,与浏览器无关。
- client:使用区、客户区。指的是客户区,当然是指浏览器区域。
- offset:偏移。指的是目标甲相对目标乙的距离。
- scroll:卷轴、卷动。指的是包含滚动条的的属性。
- inner:内部。指的是内部部分,不含滚动条。
- avail:可用的。可用区域,不含滚动条,易与inner混淆。
窗口位置
screenLeft 和 screenTop
IE、Safari、Opera和Chrome都提供了screenLeft和screenTop属性,分别用来表示窗口相对于屏幕左边和上边的位置。
表示:
- ie、opera浏览器的内边缘距离屏幕边缘的距离。
- chrome、Safari浏览器的外边缘距离屏幕边缘的距离。
screenX 和 screenY
Firefox则在这两个属性中提供相同的窗口位置信息,Safari与Chrome同样也支持这两个属性。
Opera虽然也支持这两个属性,但与screenLeft和screenTop属性并不对应,因此最好不要在Opera中使用screenX 和 screenY。
使用下列代码可以跨浏览器取得窗口左边和上边的位置:
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的值
但是各个浏览器对于这四个属性返回值的设定有很大差异,最终结果就是无法再跨浏览器的条件下取得窗口左边和上边的精确坐标值。
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);
这两个方法可能被浏览器禁用。
而且这两个方法都不适用于框架,只能对最外层的window对象使用。
窗口大小
跨浏览器确定一个窗口的大小也不是一件简单的事,其中有四个属性:
innerWidth、innerHeight、outerWidth、outerHeight
- inner……:浏览器可见区域的内宽度、高度(不含浏览器的边框,但包含滚动条)。
- outer……:浏览器外宽度(包含浏览器的边框,因各个浏览器的边框不一样,得到的值也是不一样的)。
各浏览器的差异较大……不想展开了……
resizeTo() resizeBy()
这两个方法可以调整浏览器窗口的大小。都接收两个参数:
- window.resizeTo( ):新宽度和新高度
- window.resizeBy( ):新窗口与原窗口的宽度和高度之差
//调整到100*100
window.resizeTo(100,100);
//调整到200*150
window.resiezeBy(100,50);
//调整到300*300
window.resizeTo(300,300);
但这两个方法和移动窗口位置的方法类似,也有可能被浏览器禁用。
而且这两个方法都不适用于框架,只能对最外层的window对象使用。
导航和打开窗口
window.open()
既可以导航到一个特定的URL,也可以打开一个新的浏览器窗口
接收4个参数:
- 要加载的URL
- 窗口目标
- 一个特性字符串
- 一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值
- 如果window.open()传递了第二个参数,而且该参数是已有窗口或框架的名称,那么就会在具有该名称的窗口或框架中加载第一个参数指定的URL。
- 如果传递的第二个参数并不是一个已经存在的窗口或框架,那么该方法就会根据第三个参数传入的字符串创建一个新窗口或新标签页。如果没有传入第三个参数,就会打开一个带有全部默认设置的新浏览器窗口。
第三个参数是一个逗号分隔的设置字符串,表示在新窗口中都显示哪些特性。
window.open()方法会返回一个指向新窗口的引用。
var wroxWin = window.open(//一系列参数……)
//调整大小
wroxWin.resizeTo(500,500);
//移动位置
wroxWin.moveTo(100,100);
//调用close()方法还可以关闭新打开的窗口
wroxWin.close();
但是close()这个方法仅适用于通过window.open打开的弹出窗口。
弹出窗口关闭后,窗口的引用还在,但除了像下面这样检测其closed属性之外已经没有其他用处了。
wroxWin.closed; //true1
新创建的window对象有一个opener属性,其中保存着打开它的原始窗口对象。
var wroxWin = window.open(//一系列参数……);
wroxWin.opener == window; //true
虽然弹出窗口有一个指针指向打开它的原始窗口,但是原始窗口中并没有这样的指针指向弹出窗口。窗口并不跟踪记录他们打开的弹出窗口。
可以将新创建标签页的opener属性设置为null,即告诉浏览器新创建的标签页不需要与打开它的标签页通信,可以在独立的进程中运行。而这种联系一旦切断,无法恢复
wroxWin.opener = null;
alert() confirm() prompt()
这三个方法可以调用系统对话框向用户显示消息。
通过这几个方法打开的对话框都是同步和模态的。也就是说,显示这些对话框的时候代码会停止执行,关掉后代码又会恢复执行。
-
alert:包含指定文本和一个确定按钮。
-
confirm:多了取消按钮。
可以检查confirm方法返回的布尔值来确定用户是点击了确定还是取消。 -
prompt:除了确定和取消按钮,还有一个文本输入框。接收两个参数:
- 要显示给用户的文本提示
- 文本输入域的默认值(可以是一个空字符串)
如果用户单击了确定,会返回文本输入域的值。如果点击取消则返回null。
var result = prompt("what is your name?","");
if(result != null){
alert("welcome,"+result)
}
还有两个可以通过js打开的对话框,即查找和打印。这两个对话框都是异步显示的,能够将控制权立即交还给脚本。这两个对话框与用户通过浏览器菜单的查找和打印命令打开的对话框相同。
window.print();
window.find();
location对象
location对象既是window对象的属性,也是document对象的属性;换句话说,window.location和document.location引用的是同一个对象。
location的用处在于它将URL解析为独立的片段。
location对象有以下属性:
- location.hash:返回URL中#后面的字符串,如”#content”
- location.host:返回服务器名称和端口号,“www.baidu.com:80”
- location.hostname:返回不带端口号的服务器名称,“www.baidu.com”
- location.href:返回当前加载页面的完整URL。location对象的toString()方法也返回这个值。“http://www.baidu.com”
- location.pathname:返回URL中的目录或文件名,”/zh-CN/docs/Web/API/Window/location”
- location.port:返回URL中指定的端口号,若未指定则返回空字符串,“8080”
- location.protocol:返回页面使用的协议,通常是http或https,”https”
- location.search:返回URL的查询字符串,这个字符串以?开头。“?q=javascript”
使用location对象可以通过很多方式来改变浏览器的位置。
- asign()
location.assign("http://www.wrox.com");
这样就可以立即打开新URL并在浏览器的历史记录中生成一条记录。
如果是将location.href或window.location设置为一个URL值,也会以该值立即调用assign()方法。
以下两条代码与直接调用assign代码效果完全一样。
location.href = "http://www.wrox.com";
window.location = "http://www.wrox.com";
另外,改变location对象其他属性值也可以改变当前加载的页面,如改变hash、hostname、search、pathname、port。
每次修改location的属性**(hash除外)**,页面都会以新URL重新加载。
- replace()
当通过上述任何一种方式修改URL后,浏览器的历史记录中就会生成一条新纪录,因此用户通过单击“后退”按钮就可以导航到前一个页面。
要禁用这种行为,可以使用replace()方法。
此方法接收一个参数,即要导航到的URL。浏览器的位置虽然会改变,但是不会在历史记录中生成新记录。
在调用replace()方法后,用户不能回到前一个页面。
- reload()
作用是重新加载当前显示的页面。
- 如果不传递任何参数,页面就会以最有效的方式重新加载,也就是说,如果页面自上次请求以来没有改变过,页面就会从浏览器缓存中重新加载。
- 如果要强制从服务器重新加载,则需要传递参数true。
位于reload后面的代码可能会执行也可能不会执行,取决于网络延迟或系统资源等因素,因此最好将reload放在代码的最后一行。
navigator对象
navigator对象已经成为识别客户端浏览器的事实标准。
有各项属性来获取浏览器的信息,先不详细展开。
screen对象
screen对象基本只用来表明客户端的能力,如浏览器窗口外部显示器信息,像素宽度和高度等。在编程中用处不大。
history对象
history对象保存着用户上网的历史记录,从窗口被打开的那一刻算起。
出于安全方面的考虑,开发人员无法得知用户访问过的URL,但借由用户访问过的页面列表,同样可以在不知道实际URL的情况下实现后退和前进。
- go()
使用go方法可以在用户的历史记录中任意跳转,可以向后也可以向前。
此方法接收一个参数:表示向后或向前跳转的页数的一个整数值。
- 负数表示向后跳转(类似浏览器的后退)
- 正数表示向前跳转(类似浏览器的前进)
//后退一页
history.go(-1);
//前进一页
history.go(1);
//前进两页
history.go(2);
也可以给go方法传递一个字符串参数,此时浏览器会跳转到历史记录中包含该字符串的第一个位置,可能后退也可能前进,具体要看哪个位置最近。如果历史记录中不包含该字符串,那么这个方法什么都不做。
//跳转到最近的wrox.com页面
history.go("wrox.com");
//跳转到最近的nczonline.net页面
history.go("nczonline.net");
- forward()和back()
代替go,分别为前进和后退。
//后退一页
history.back();
//前进一页
history.forword();
- length属性
保存着历史记录的数量,包括所有历史记录。
对于第一个页面而言,history.length等于0.
通过像下面这样测试该属性的值,可以确定用户是否一开始就打开了你的页面:
if(history.length == 0){
//这应该是用户打开窗口后的第一个页面
}
html5为history API添加了pushState()方法、replaceState ()方法与popstate事件。都是支持到IE10.
-
pushState()
用于向浏览器的历史记录中添加一条新记录,同时改变地址栏的地址内容,但并不刷新页面。
接收三个参数:
- state对象:一个对象或者字符串,用于描述新记录的一些特性。这个参数会被一并添加到历史记录中,以供以后使用。这个参数是开发者根据自己的需要自由给出的。
- title:一个字符串,代表新页面的标题。当前基本上所有浏览器都会忽略这个参数
- URL:一个字符串,代表新页面的相对地址。
var state = {foo:1,bar:2};
history.push(state,'test','/test')
- replaceState()
有时,你希望不添加一个新记录,而是替换当前的记录,则可以使用replaceState方法。这个方法和pushState的参数完全一样。 - popstate事件
当用户点击浏览器的「前进」、「后退」按钮时,就会触发popstate事件。
需要注意的是调用history.pushState()
或history.replaceState()
不会触发popstate事件,只有用户的浏览器动作才会触发该事件。
window.addEventListener("popstate",function(e){
var state = e.state;
})
这里事件对象的state属性就是我们调用pushState方法时传入的第一个参数。