一、BOM
1. 什么是BOM?
BOM(Browser Object Mode) 是指浏览器对象模型,是用于描述这种对象与对象之间层次关系的模型,浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。BOM由多个对象组成,其中代表浏览器窗口的Window对象是BOM的顶层对象,其他对象都是该对象的子对象。
2. Window对象
2.1 框架与窗口关系
Window对象是指当前代码所存在的框架实例,在没有引入框架的情况下指的是浏览器窗口。同时需要了解其他窗口关系:
- Window对象:指当前代码所存在的框架实例
- Top对象:任何时候都指向最顶层框架,也就是浏览器窗口
- Parent对象:指当前框架的直接上层框架
- self对象:始终指向window,和window可以互换使用
2.2 窗口位置与大小
窗口位置我暂时没有想到什么应用的场合,这里主要讨论窗口大小的问题。IE9+、 Firefox、 Safari、 Opera 和 Chrome均提供了innerWidth、 innerHeight、 outerWidth 和 outerHeight属性来确定窗口信息。而IE8以下版本不支持该属性,不过它通过DOM提供了窗口相关信息:document.documentElement.clientWidth来保存页面视口的宽度。在IE6中,这些属性只在标准模式下才有效,而在混合模式下,就必须通过document.body.clientWidth来保存相同的信息。
//兼容性代码如下 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; } }
而对于移动设备也存在同样的问题。主流浏览器支持window.innerWidth保存可见视口,而IE浏览器不支持该属性,采用document.documentElement.clientWidth来保存页面宽度信息。
//移动端兼容性代码(在响应式布局时最好先判断是否为移动端) windows.innerWidth ? windows.innerWidth : document.body.clientWidth; windows.innerHeight ? windows.innerHeight : document.body.clientHeight;
注:innerWidth可读可写,而clientWidth是只读的。
2.3 导航与打开窗口
2.3.1 使用window.open()可以导航到一个特定的URL,也可以打开一个新的浏览器窗口。
实例:var wroxWin = window.open("http://www.wrox.com/","wroxWindow", "height=400,width=400,top=10,left=10,resizable=yes");
其中第一个参数代表目的URL,第二个代表在已有或新建框架"wroxWindow"下加载页面,第三个参数代表新窗口都显示哪些特性。
而且使用resizeTo/ moveTo/ close()对新弹出的窗口进行编辑。
2.3.2 窗口被禁用弹出
禁止窗口弹出可能是浏览器内置的屏蔽程序,此时window.open()会返回null;还有可能是其他屏蔽工具,这是该条语句会导致错误。鉴于禁止弹窗分为两种情况,我们需要将windo.open()封装在一个try-catch块中。
var blocked = false; try { var wroxWin = window.open("http://www.wrox.com", "_blank"); if (wroxWin == null){ blocked = true; } } catch (ex){ blocked = true; } if (blocked){ alert("The popup was blocked!"); }
2.4 超时调用和间歇调用
2.4.1 超时调用 setTimeOut()
超时调用共传递两个参数,要执行的代码和一毫秒表示的时间。因为以字符串形式传递代码可能会影响性能,所以不建议传递字符串。
//不建议传递字符串! setTimeout("alert(‘Hello world!‘) ", 1000); //推荐的调用方式 setTimeout(function() { alert("Hello world!"); }, 1000);
调用 setTimeout() 之后,该方法会返回一个数值 ID,表示超时调用。这个超时调用 ID 是计划执行代码的唯一标识符,可以通过它来取消超时调用。要取消尚未执行的超时调用计划,可以调用clearTimeout() 方法并将相应的超时调用 ID 作为参数传递给它,如下所示。
//设置超时调用 var timeoutId = setTimeout(function() { alert("Hello world!"); }, 1000); //注意:把它取消 clearTimeout(timeoutId);
注:超时调用的代码都是在全局作用域中执行的,因此函数中 this 的值在非严格模式下指向 window 对象,在严格模式下是 undefined。
2.4.2 间歇调用 setInterval()
调用 setInterval() 方法同样也会返回一个间歇调用 ID,该 ID 可用于在将来某个时刻取消间歇调用。要取消尚未执行的间歇调用,可以使用 clearInterval() 方法并传入相应的间歇调用 ID。取消间歇调用的重要性要远远高于取消超时调用,因为在不加干涉的情况下,间歇调用将会一直执行到页面卸载。以下是一个常见的使用间歇调用的例子。
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);
可见,在使用超时调用时,没有必要跟踪超时调用 ID,因为每次执行代码之后,如果不再设置另一次超时调用,调用就会自行停止。一般认为,使用超时调用来模拟间歇调用的是一种最佳模式。在开发环境下,很少使用真正的间歇调用,原因是后一个间歇调用可能会在前一个间歇调用结束之前启动。而像前面示例中那样使用超时调用,则完全可以避免这一点。所以,最好不要使用间歇调用。