天天看點

BOM之window 對象

BOM之window 對象

    • 8.1 window 對象
      • 8.1.1 全局作用域
      • 8.1.2 視窗關系及架構
      • 8.1.3 視窗位置
      • 8.1.4 視窗大小
      • 8.1.5 導航和打開視窗
        • 1. 彈出視窗
        • 2. 安全限制
        • 3. 彈出視窗屏蔽程式
      • 8.1.6 間歇調用和逾時調用
        • 1. 逾時調用
        • 2. 間歇調用setInterval()
      • 8.1.7 系統對話框
        • 1. alert()
        • 2. confirm()
        • 3.prompt()

8.1 window 對象

在網頁中定義的任何一個對象、變量和函數,都以 window 作為其 Global 對象,是以有權通路parseInt()等方法

8.1.1 全局作用域

var age = 29;
function sayAge(){
	alert(this.age);
}
alert(window.age); //29
sayAge(); //29
window.sayAge(); //29
           

抛開全局變量會成為 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 對象,可以知

道某個可能未聲明的變量是否存在。例如:

//這裡會抛出錯誤,因為 oldValue 未定義
var newValue = oldValue;
//這裡不會抛出錯誤,因為這是一次屬性查詢
//newValue 的值是 undefined
var newValue = window.oldValue;
           
Windows Mobile 平台的 IE 浏覽器不允許通過 window.property = value 之類的形式,直接在 window 對象上建立新的屬性或方法。可是,在全局作用域中聲明的所有變量和函數,照樣會變成 window 對象的成員。

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。顧名思義, parent(父)對象始終指向目前架構的直接上層架構。在某些情況下, parent 有可能等于 top;但在沒有架構的情況下, parent 一定等于top(此時它們都等于 window)。

除非最高層視窗是通過 window.open()打開的(本章後面将會讨論),否則其 window 對象的 name 屬性不會包含任何值。

在使用架構的情況下,浏覽器中會存在多個 Global 對象。在每個架構中定義的全局變量會自動成為架構中 window 對象的屬性。由于每個 window 對象都包含原生類型的構造函數,是以每個架構都有一套自己的構造函數,這些構造函數一一對應,但并不相等。例如, top.Object 并不等于 top.frames[0].Object。這個問題會影響到對跨架構傳遞的對象使用 instanceof 操作符。

8.1.3 視窗位置

IE、 Safari、 Opera 和 Chrome 都提供了screenLeft 和 screenTop 屬性,分别用于表示視窗相對于螢幕左邊和上邊的位置。 Firefox 則在screenX 和 screenY 屬性中提供相同的視窗位置資訊, Safari 和 Chrome 也同時支援這兩個屬性。 Opera雖然也支援 screenX 和 screenY 屬性,但與 screenLeft 和 screenTop 屬性并不對應,是以建議大家不要在 Opera 中使用它們。使用下列代碼可以跨浏覽器取得視窗左邊和上邊的位置。

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 的值。在使用這些值的過程中,還必須注意一些小問題。在 IE、 Opera 中, screenLeft 和 screenTop 中儲存的是從螢幕左邊和上邊到由 window 對象表示的頁面可見區域的距離。換句話說,如果 window 對象是最外層對象,而且浏覽器視窗緊貼螢幕最上端——即 y 軸坐标為 0,那麼 screenTop 的值就是位于頁面可見區域上方的浏覽器工具欄的像素高度。但是,在 Chrome、 Firefox 和 Safari 中, screenY 或 screenTop中儲存的是整個浏覽器視窗相對于螢幕的坐标值,即在視窗的 y 軸坐标為 0 時傳回 0。

更讓人捉摸不透是, Firefox、 Safari 和 Chrome 始終傳回頁面中每個架構的 top.screenX 和top.screenY 值。即使在頁面由于被設定了外邊距而發生偏移的情況下,相對于 window 對象使用screenX 和 screenY 每次也都會傳回相同的值。而 IE 和 Opera 則會給出架構相對于螢幕邊界的精确坐

标值。

使用 moveTo()和 moveBy()方法倒是有可能将視窗精确地移動到一個新位置。

//将視窗移動到螢幕左上角
window.moveTo(0,0);
//将窗向下移動 100 像素
window.moveBy(0,100);
//将視窗移動到(200,300)
window.moveTo(200,300);
//将視窗向左移動 50 像素
window.moveBy(-50,0);
           

8.1.4 視窗大小

IE9+、 Firefox、 Safari、 Opera 和 Chrome 均為此提供了 4 個屬性: innerWidth、 innerHeight、 outerWidth 和 outerHeight。

  • 在 IE9+、 Safari 和 Firefox中, outerWidth 和 outerHeight 傳回浏覽器視窗本身的尺寸(無論是從最外層的 window 對象還是從某個架構通路)。
  • 在 Opera 中,這兩個屬性的值表示頁面視圖容器( Opera 中單個标簽頁對應的浏覽器視窗)的大小。而 innerWidth 和 innerHeight則表示該容器中頁面視圖區的大小(減去邊框寬度)。
  • 在 Chrome 中, outerWidth、 outerHeight 與innerWidth、 innerHeight 傳回相同的值,即視口(viewport)大小而非浏覽器視窗大小。

在 IE、Firefox、Safari、Opera 和 Chrome 中, document.documentElement.clientWidth 和

document.documentElement.clientHeight 中儲存了頁面視口的資訊。在 IE6 中,這些屬性必須在标準模式下才有效;如果是混雜模式,就必須通過 document.body.clientWidth 和 document.body.clientHeight 取得相同資訊。而對于混雜模式下的Chrome,則無論通過 document.documentElement 還是 document.body 中的 clientWidth 和 clientHeight 屬性,都可以取得視口的大小。

雖然最終無法确定浏覽器視窗本身的大小,但卻可以取得頁面視口的大小,如下所示。

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 和 window.innerHeight 儲存着可見視口,也就是螢幕上可見頁面區域的大小。移動 IE 浏覽器不支援這些屬性,但通過 document.documentElement.clientWidth 和 document.documentElement.clientHeihgt 提供了相同的資訊。随着頁面的縮放,這些值也會相應變化。

在其他移動浏覽器中, document.documentElement 度量的是布局視口,即渲染後頁面的實際大小(與可見視口不同,可見視口隻是整個頁面中的一小部分)。移動 IE 浏覽器把布局視口的資訊儲存在document.body.clientWidth 和document.body.clientHeight 中。這些值不會随着頁面縮放變化。

使用 resizeTo()和 resizeBy()方法可以調整浏覽器視窗的大小。

//調整到 100× 100
window.resizeTo(100, 100);
//調整到 200× 150
window.resizeBy(100, 50);
//調整到 300× 300
window.resizeTo(300, 300);
           

8.1.5 導航和打開視窗

使用 window.open()方法既可以導航到一個特定的 URL,也可以打開一個新的浏覽器視窗。這個方法可以接收 4 個參數:要加載的 URL、視窗目标、一個特性字元串以及一個表示新頁面是否取代浏覽器曆史記錄中目前加載頁面的布爾值。通常隻須傳遞第一個參數,最後一個參數隻在不打開新視窗的情況下使用。如果為 window.open()傳遞了第二個參數,而且該參數是已有視窗或架構的名稱,那麼就會在具有該名稱的視窗或架構中加載第一個參數指定的 URL。

//等同于< a href="http://www.wrox.com" target="_blank" rel="external nofollow"  target="topFrame"></a>
window.open("http://www.wrox.com/", "topFrame");
           

如果有一個名叫"topFrame"的視窗或者架構,就會在該視窗或架構加載這個 URL;否則,就會建立一個新視窗并将其命名為"topFrame"。此外,第二個參數也可以是下列任何一個特殊的視窗名稱: _self、 _parent、 _top 或_blank。

1. 彈出視窗

如果給 window.open()傳遞的第二個參數并不是一個已經存在的視窗或架構,那麼該方法就會根據在第三個參數位置上傳入的字元串建立一個新視窗或新标簽頁。如果沒有傳入第三個參數,那麼就會打開一個帶有全部預設設定(工具欄、位址欄和狀态欄等)的新浏覽器視窗(或者打開一個新标簽頁——根據浏覽器設定)。在不打開新視窗的情況下,會忽略第三個參數。

BOM之window 對象

表中所列的部分或全部設定選項,都可以通過逗号分隔的名值對清單來指定。

var wroxWin = window.open("http://www.wrox.com/","wroxWindow",
"height=400,width=400,top=10,left=10,resizable=yes");
//調整大小
wroxWin.resizeTo(500,500);
//移動位置
wroxWin.moveTo(100,100);
調用 close()方法還可以關閉新打開的視窗。
wroxWin.close();
alert(wroxWin.closed); //true
wroxWin.opener = null;
           

将 opener 屬性設定為 null 就是告訴浏覽器新建立的标簽頁不需要與打開它的标簽頁通信,是以可以在獨立的程序中運作。标簽頁之間的聯系一旦切斷,将沒有辦法恢複。

2. 安全限制

Windows XP SP2 中的 IE6 對彈出視窗施加了多方面的安全限制,包括不允許在螢幕之外建立彈出視窗、不允許将彈出視窗移動到螢幕以外、不允許關閉狀态欄等。 IE7 則增加了更多的安全限制,如不允許關閉位址欄、預設情況下不允許移動彈出視窗或調整其大小。 Firefox 1 從一開始就不支援修改狀态欄,是以無論給 window.open()傳入什麼樣的特性字元串,彈出視窗中都會無一例外地顯示狀态欄。後來的 Firefox 3 又強制始終在彈出視窗中顯示位址欄。 Opera 隻會在主浏覽器視窗中打開彈出視窗,但不允許它們出現在可能與系統對話框混淆的地方。

此外,有的浏覽器隻根據使用者操作來建立彈出視窗。這樣一來,在頁面尚未加載完成時調用window.open()的語句根本不會執行,而且還可能會将錯誤消息顯示給使用者。換句話說,隻能通過單擊或者擊鍵來打開彈出視窗。

對于那些不是使用者有意打開的彈出視窗, Chrome 采取了不同的處理方式。它不會像其他浏覽器那樣簡單地屏蔽這些彈出視窗,而是隻顯示它們的标題欄,并把它們放在浏覽器視窗的右下角

3. 彈出視窗屏蔽程式

如果是浏覽器内置的屏蔽程式阻止的彈出視窗,那麼 window.open()很可能會傳回 null。

如果是浏覽器擴充或其他程式阻止的彈出視窗,那麼 window.open()通常會抛出一個錯誤。是以,要想準确地檢測出彈出視窗是否被屏蔽,必須在檢測傳回值的同時,将對 window.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!");
}
           

檢測彈出視窗是否被屏蔽隻是一方面,它并不會阻止浏覽器顯示與被屏蔽的彈出視窗有關的消息。

8.1.6 間歇調用和逾時調用

1. 逾時調用

逾時調用需要使用 window 對象的 setTimeout()方法,它接受兩個參數:要執行的代碼和以毫秒表示的時間(即在執行代碼前需要等待多少毫秒)。其中,第一個參數可以是一個包含 JavaScript 代碼的字元串(就和在 eval()函數中使用的字元串一樣),也可以是一個函數。例如,下面對 setTimeout()的兩次調用都會在一秒鐘後顯示一個警告框。

//不建議傳遞字元串!
setTimeout("alert('Hello world!') ", 1000);
//推薦的調用方式
setTimeout(function() {
	alert("Hello world!");
}, 1000);
           
由于傳遞字元串可能導緻性能損失,是以不建議以字元串作為第一個參數。

第二個參數是一個表示等待多長時間的毫秒數,但經過該時間後指定的代碼不一定會執行。JavaScript 是一個單線程式的解釋器,是以一定時間内隻能執行一段代碼。為了控制要執行的代碼,就有一個 JavaScript 任務隊列。這些任務會按照将它們添加到隊列的順序執行。 setTimeout()的第二個參數告訴 JavaScript 再過多長時間把目前任務添加到隊列中。如果隊列是空的,那麼添加的代碼會立即執行;如果隊列不是空的,那麼它就要等前面的代碼執行完了以後再執行。調用 setTimeout()之後,該方法會傳回一個數值 ID,表示逾時調用。這個逾時調用 ID 是計劃執行代碼的唯一辨別符,可以通過它來取消逾時調用。要取消尚未執行的逾時調用計劃,可以調用**clearTimeout()**方法并将相應的逾時調用 ID 作為參數傳遞給它,如下所示。

//設定逾時調用
var timeoutId = setTimeout(function() {
	alert("Hello world!");
}, 1000);
//注意:把它取消
clearTimeout(timeoutId);
           

逾時調用的代碼都是在全局作用域中執行的,是以函數中 this 的值在非嚴格模

式下指向 window 對象,在嚴格模式下是 undefined

2. 間歇調用setInterval()

//不建議傳遞字元串!
setInterval ("alert('Hello world!') ", 10000);
//推薦的調用方式
setInterval (function() {
	alert("Hello world!");
}, 10000);
           

調用 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);
IntervalExample02.
           
一般認為,使用逾時調用來模拟間歇調用的是一種最佳模式。在開發環境下,很少使用真正的間歇調用,原因是後一個間歇調用可能會在前一個間歇調用結束之前啟動。
var num = 0;
var max = 10;
function incrementNumber() {
	num++;
	//如果執行次數未達到 max 設定的值,則設定另一次逾時調用
	if (num < max) {
		setTimeout(incrementNumber, 500);
	} else {
		alert("Done");
	}
}
setTimeout(incrementNumber, 500);
           

8.1.7 系統對話框

浏覽器通過 alert()、 **confirm()和 prompt()**方法可以調用系統對話框向使用者顯示消息。系統對話框與在浏覽器中顯示的網頁沒有關系,也不包含 HTML。它們的外觀由作業系統及(或)浏覽器設定決定,而不是由 CSS 決定。此外,通過這幾個方法打開的對話框都是同步和模态的。也就是說,顯示這些對話框的時候代碼會停止執行,而關掉這些對話框後代碼又會恢複執行。

1. alert()

2. confirm()

if (confirm("Are you sure?")) {
	alert("I'm so glad you're sure! ");
} else {
	alert("I'm sorry to hear you're not sure. ");
}
           

3.prompt()

var result = prompt("What is your name? ", "文本輸入域的預設值");
if (result !== null) {
	alert("Welcome, " + result);
}
           

Google Chrome 浏覽器還引入了一種新特性。如果目前腳本在執行過程中會打開兩個或多個對話框,那麼從第二個對話框開始,每個對話框中都會顯示一個複選框,以便使用者阻止後續的對話框顯示,除非使用者重新整理頁面。

還有兩個可以通過 JavaScript 打開的對話框,即“查找”和“列印”。這兩個對話框都是異步顯示的,能夠将控制權立即交還給腳本。這兩個對話框與使用者通過浏覽器菜單的“查找”和“列印”指令打開的對話框相同。而在 JavaScript 中則可以像下面這樣通過 window 對象的 find()和 print()方法打開它們。

//顯示“列印”對話框
window.print();
//顯示“查找”對話框
window.find();