JavaScript window 對象

2023-03-20 15:46 更新

概述 

瀏覽器里面,window對象(注意,w為小寫)指當(dāng)前的瀏覽器窗口。它也是當(dāng)前頁面的頂層對象,即最高一層的對象,所有其他對象都是它的下屬。一個變量如果未聲明,那么默認(rèn)就是頂層對象的屬性。

a = 1;
window.a // 1

上面代碼中,a是一個沒有聲明就直接賦值的變量,它自動成為頂層對象的屬性。

window有自己的實體含義,其實不適合當(dāng)作最高一層的頂層對象,這是一個語言的設(shè)計失誤。最早,設(shè)計這門語言的時候,原始設(shè)想是語言內(nèi)置的對象越少越好,這樣可以提高瀏覽器的性能。因此,語言設(shè)計者 Brendan Eich 就把window對象當(dāng)作頂層對象,所有未聲明就賦值的變量都自動變成window對象的屬性。這種設(shè)計使得編譯階段無法檢測出未聲明變量,但到了今天已經(jīng)沒有辦法糾正了。

window 對象的屬性 

window.name 

window.name屬性是一個字符串,表示當(dāng)前瀏覽器窗口的名字。窗口不一定需要名字,這個屬性主要配合超鏈接和表單的target屬性使用。

window.name = 'Hello World!';
console.log(window.name)
// "Hello World!"

該屬性只能保存字符串,如果寫入的值不是字符串,會自動轉(zhuǎn)成字符串。各個瀏覽器對這個值的儲存容量有所不同,但是一般來說,可以高達(dá)幾MB。

只要瀏覽器窗口不關(guān)閉,這個屬性是不會消失的。舉例來說,訪問a.com時,該頁面的腳本設(shè)置了window.name,接下來在同一個窗口里面載入了b.com,新頁面的腳本可以讀到上一個網(wǎng)頁設(shè)置的window.name。頁面刷新也是這種情況。一旦瀏覽器窗口關(guān)閉后,該屬性保存的值就會消失,因為這時窗口已經(jīng)不存在了。

window.closed,window.opener 

window.closed屬性返回一個布爾值,表示窗口是否關(guān)閉。

window.closed // false

上面代碼檢查當(dāng)前窗口是否關(guān)閉。這種檢查意義不大,因為只要能運行代碼,當(dāng)前窗口肯定沒有關(guān)閉。這個屬性一般用來檢查,使用腳本打開的新窗口是否關(guān)閉。

var popup = window.open();

if ((popup !== null) && !popup.closed) {
  // 窗口仍然打開著
}

window.opener屬性表示打開當(dāng)前窗口的父窗口。如果當(dāng)前窗口沒有父窗口(即直接在地址欄輸入打開),則返回null。

window.open().opener === window // true

上面表達(dá)式會打開一個新窗口,然后返回true。

如果兩個窗口之間不需要通信,建議將子窗口的opener屬性顯式設(shè)為null,這樣可以減少一些安全隱患。

var newWin = window.open('example.html', 'newWindow', 'height=400,width=400');
newWin.opener = null;

上面代碼中,子窗口的opener屬性設(shè)為null,兩個窗口之間就沒辦法再聯(lián)系了。

通過opener屬性,可以獲得父窗口的全局屬性和方法,但只限于兩個窗口同源的情況(參見《同源限制》一章),且其中一個窗口由另一個打開。<a>元素添加rel="noopener"屬性,可以防止新打開的窗口獲取父窗口,減輕被惡意網(wǎng)站修改父窗口 URL 的風(fēng)險。

<a  rel="external nofollow" target="_blank"  target="_blank" rel="noopener">
惡意網(wǎng)站
</a>

window.self,window.window 

window.selfwindow.window屬性都指向窗口本身。這兩個屬性只讀。

window.self === window // true
window.window === window // true

window.frames,window.length 

window.frames屬性返回一個類似數(shù)組的對象,成員為頁面內(nèi)所有框架窗口,包括frame元素和iframe元素。window.frames[0]表示頁面中第一個框架窗口。

如果iframe元素設(shè)置了idname屬性,那么就可以用屬性值,引用這個iframe窗口。比如<iframe name="myIFrame">可以用frames['myIFrame']或者frames.myIFrame來引用。

frames屬性實際上是window對象的別名。

frames === window // true

因此,frames[0]也可以用window[0]表示。但是,從語義上看,frames更清晰,而且考慮到window還是全局對象,因此推薦表示多窗口時,總是使用frames[0]的寫法。更多介紹請看下文的《多窗口操作》部分。

window.length屬性返回當(dāng)前網(wǎng)頁包含的框架總數(shù)。如果當(dāng)前網(wǎng)頁不包含frameiframe元素,那么window.length就返回0。

window.frames.length === window.length // true

上面代碼表示,window.frames.lengthwindow.length應(yīng)該是相等的。

window.frameElement 

window.frameElement屬性主要用于當(dāng)前窗口嵌在另一個網(wǎng)頁的情況(嵌入<object>、<iframe><embed>元素),返回當(dāng)前窗口所在的那個元素節(jié)點。如果當(dāng)前窗口是頂層窗口,或者所嵌入的那個網(wǎng)頁不是同源的,該屬性返回null。

// HTML 代碼如下
// <iframe src="about.html"></iframe>

// 下面的腳本在 about.html 里面
var frameEl = window.frameElement;
if (frameEl) {
  frameEl.src = 'other.html';
}

上面代碼中,frameEl變量就是<iframe>元素。

window.top,window.parent 

window.top屬性指向最頂層窗口,主要用于在框架窗口(frame)里面獲取頂層窗口。

window.parent屬性指向父窗口。如果當(dāng)前窗口沒有父窗口,window.parent指向自身。

if (window.parent !== window.top) {
  // 表明當(dāng)前窗口嵌入不止一層
}

對于不包含框架的網(wǎng)頁,這兩個屬性等同于window對象。

window.status 

window.status屬性用于讀寫瀏覽器狀態(tài)欄的文本。但是,現(xiàn)在很多瀏覽器都不允許改寫狀態(tài)欄文本,所以使用這個方法不一定有效。

window.devicePixelRatio 

window.devicePixelRatio屬性返回一個數(shù)值,表示一個 CSS 像素的大小與一個物理像素的大小之間的比率。也就是說,它表示一個 CSS 像素由多少個物理像素組成。它可以用于判斷用戶的顯示環(huán)境,如果這個比率較大,就表示用戶正在使用高清屏幕,因此可以顯示較大像素的圖片。

位置大小屬性 

以下屬性返回window對象的位置信息和大小信息。

(1)window.screenX,window.screenY

window.screenXwindow.screenY屬性,返回瀏覽器窗口左上角相對于當(dāng)前屏幕左上角的水平距離和垂直距離(單位像素)。這兩個屬性只讀。

(2) window.innerHeight,window.innerWidth

window.innerHeightwindow.innerWidth屬性,返回網(wǎng)頁在當(dāng)前窗口中可見部分的高度和寬度,即“視口”(viewport)的大?。▎挝幌袼兀?。這兩個屬性只讀。

用戶放大網(wǎng)頁的時候(比如將網(wǎng)頁從100%的大小放大為200%),這兩個屬性會變小。因為這時網(wǎng)頁的像素大小不變(比如寬度還是960像素),只是每個像素占據(jù)的屏幕空間變大了,因此可見部分(視口)就變小了。

注意,這兩個屬性值包括滾動條的高度和寬度。

(3)window.outerHeight,window.outerWidth

window.outerHeightwindow.outerWidth屬性返回瀏覽器窗口的高度和寬度,包括瀏覽器菜單和邊框(單位像素)。這兩個屬性只讀。

(4)window.scrollX,window.scrollY

window.scrollX屬性返回頁面的水平滾動距離,window.scrollY屬性返回頁面的垂直滾動距離,單位都為像素。這兩個屬性只讀。

注意,這兩個屬性的返回值不是整數(shù),而是雙精度浮點數(shù)。如果頁面沒有滾動,它們的值就是0

舉例來說,如果用戶向下拉動了垂直滾動條75像素,那么window.scrollY就是75左右。用戶水平向右拉動水平滾動條200像素,window.scrollX就是200左右。

if (window.scrollY < 75) {
  window.scroll(0, 75);
}

上面代碼中,如果頁面向下滾動的距離小于75像素,那么頁面向下滾動75像素。

(5)window.pageXOffset,window.pageYOffset

window.pageXOffset屬性和window.pageYOffset屬性,是window.scrollXwindow.scrollY別名。

組件屬性 

組件屬性返回瀏覽器的組件對象。這樣的屬性有下面幾個。

  • window.locationbar:地址欄對象
  • window.menubar:菜單欄對象
  • window.scrollbars:窗口的滾動條對象
  • window.toolbar:工具欄對象
  • window.statusbar:狀態(tài)欄對象
  • window.personalbar:用戶安裝的個人工具欄對象

這些對象的visible屬性是一個布爾值,表示這些組件是否可見。這些屬性只讀。

window.locationbar.visible
window.menubar.visible
window.scrollbars.visible
window.toolbar.visible
window.statusbar.visible
window.personalbar.visible

全局對象屬性 

全局對象屬性指向一些瀏覽器原生的全局對象。

  • window.document:指向document對象,詳見《document 對象》一章。注意,這個屬性有同源限制。只有來自同源的腳本才能讀取這個屬性。
  • window.location:指向Location對象,用于獲取當(dāng)前窗口的 URL 信息。它等同于document.location屬性,詳見《Location 對象》一章。
  • window.navigator:指向Navigator對象,用于獲取環(huán)境信息,詳見《Navigator 對象》一章。
  • window.history:指向History對象,表示瀏覽器的瀏覽歷史,詳見《History 對象》一章。
  • window.localStorage:指向本地儲存的 localStorage 數(shù)據(jù),詳見《Storage 接口》一章。
  • window.sessionStorage:指向本地儲存的 sessionStorage 數(shù)據(jù),詳見《Storage 接口》一章。
  • window.console:指向console對象,用于操作控制臺,詳見《console 對象》一章。
  • window.screen:指向Screen對象,表示屏幕信息,詳見《Screen 對象》一章。

window.isSecureContext 

window.isSecureContext屬性返回一個布爾值,表示當(dāng)前窗口是否處在加密環(huán)境。如果是 HTTPS 協(xié)議,就是true,否則就是false

window 對象的方法 

window.alert(),window.prompt(),window.confirm() 

window.alert()window.prompt()、window.confirm()都是瀏覽器與用戶互動的全局方法。它們會彈出不同的對話框,要求用戶做出回應(yīng)。注意,這三個方法彈出的對話框,都是瀏覽器統(tǒng)一規(guī)定的式樣,無法定制。

(1)window.alert()

window.alert()方法彈出的對話框,只有一個“確定”按鈕,往往用來通知用戶某些信息。

window.alert('Hello World');

用戶只有點擊“確定”按鈕,對話框才會消失。對話框彈出期間,瀏覽器窗口處于凍結(jié)狀態(tài),如果不點“確定”按鈕,用戶什么也干不了。

window.alert()方法的參數(shù)只能是字符串,沒法使用 CSS 樣式,但是可以用\n指定換行。

alert('本條提示\n分成兩行');

(2)window.prompt()

window.prompt()方法彈出的對話框,提示文字的下方,還有一個輸入框,要求用戶輸入信息,并有“確定”和“取消”兩個按鈕。它往往用來獲取用戶輸入的數(shù)據(jù)。

var result = prompt('您的年齡?', 25)

上面代碼會跳出一個對話框,文字提示為“您的年齡?”,要求用戶在對話框中輸入自己的年齡(默認(rèn)顯示25)。用戶填入的值,會作為返回值存入變量result。

window.prompt()的返回值有兩種情況,可能是字符串(有可能是空字符串),也有可能是null。具體分成三種情況。

  1. 用戶輸入信息,并點擊“確定”,則用戶輸入的信息就是返回值。
  2. 用戶沒有輸入信息,直接點擊“確定”,則輸入框的默認(rèn)值就是返回值。
  3. 用戶點擊了“取消”(或者按了 ESC 按鈕),則返回值是null。

window.prompt()方法的第二個參數(shù)是可選的,但是最好總是提供第二個參數(shù),作為輸入框的默認(rèn)值。

(3)window.confirm()

window.confirm()方法彈出的對話框,除了提示信息之外,只有“確定”和“取消”兩個按鈕,往往用來征詢用戶是否同意。

var result = confirm('你最近好嗎?');

上面代碼彈出一個對話框,上面只有一行文字“你最近好嗎?”,用戶選擇點擊“確定”或“取消”。

confirm方法返回一個布爾值,如果用戶點擊“確定”,返回true;如果用戶點擊“取消”,則返回false。

var okay = confirm('Please confirm this message.');
if (okay) {
  // 用戶按下“確定”
} else {
  // 用戶按下“取消”
}

confirm的一個用途是,用戶離開當(dāng)前頁面時,彈出一個對話框,問用戶是否真的要離開。

window.onunload = function () {
  return window.confirm('你確定要離開當(dāng)面頁面嗎?');
}

這三個方法都具有堵塞效應(yīng),一旦彈出對話框,整個頁面就是暫停執(zhí)行,等待用戶做出反應(yīng)。

window.open(), window.close(),window.stop() 

(1)window.open()

window.open方法用于新建另一個瀏覽器窗口,類似于瀏覽器菜單的新建窗口選項。它會返回新窗口的引用,如果無法新建窗口,則返回null

var popup = window.open('somefile.html');

上面代碼會讓瀏覽器彈出一個新建窗口,網(wǎng)址是當(dāng)前域名下的somefile.html。

open方法一共可以接受三個參數(shù)。

window.open(url, windowName, [windowFeatures])
  • url:字符串,表示新窗口的網(wǎng)址。如果省略,默認(rèn)網(wǎng)址就是about:blank。
  • windowName:字符串,表示新窗口的名字。如果該名字的窗口已經(jīng)存在,則占用該窗口,不再新建窗口。如果省略,就默認(rèn)使用_blank,表示新建一個沒有名字的窗口。另外還有幾個預(yù)設(shè)值,_self表示當(dāng)前窗口,_top表示頂層窗口,_parent表示上一層窗口。
  • windowFeatures:字符串,內(nèi)容為逗號分隔的鍵值對(詳見下文),表示新窗口的參數(shù),比如有沒有提示欄、工具條等等。如果省略,則默認(rèn)打開一個完整 UI 的新窗口。如果新建的是一個已經(jīng)存在的窗口,則該參數(shù)不起作用,瀏覽器沿用以前窗口的參數(shù)。

下面是一個例子。

var popup = window.open(
  'somepage.html',
  'DefinitionsWindows',
  'height=200,width=200,location=no,status=yes,resizable=yes,scrollbars=yes'
);

上面代碼表示,打開的新窗口高度和寬度都為200像素,沒有地址欄,但有狀態(tài)欄和滾動條,允許用戶調(diào)整大小。

第三個參數(shù)可以設(shè)定如下屬性。

  • left:新窗口距離屏幕最左邊的距離(單位像素)。注意,新窗口必須是可見的,不能設(shè)置在屏幕以外的位置。
  • top:新窗口距離屏幕最頂部的距離(單位像素)。
  • height:新窗口內(nèi)容區(qū)域的高度(單位像素),不得小于100。
  • width:新窗口內(nèi)容區(qū)域的寬度(單位像素),不得小于100。
  • outerHeight:整個瀏覽器窗口的高度(單位像素),不得小于100。
  • outerWidth:整個瀏覽器窗口的寬度(單位像素),不得小于100。
  • menubar:是否顯示菜單欄。
  • toolbar:是否顯示工具欄。
  • location:是否顯示地址欄。
  • personalbar:是否顯示用戶自己安裝的工具欄。
  • status:是否顯示狀態(tài)欄。
  • dependent:是否依賴父窗口。如果依賴,那么父窗口最小化,該窗口也最小化;父窗口關(guān)閉,該窗口也關(guān)閉。
  • minimizable:是否有最小化按鈕,前提是dialog=yes
  • noopener:新窗口將與父窗口切斷聯(lián)系,即新窗口的window.opener屬性返回null,父窗口的window.open()方法也返回null。
  • resizable:新窗口是否可以調(diào)節(jié)大小。
  • scrollbars:是否允許新窗口出現(xiàn)滾動條。
  • dialog:新窗口標(biāo)題欄是否出現(xiàn)最大化、最小化、恢復(fù)原始大小的控件。
  • titlebar:新窗口是否顯示標(biāo)題欄。
  • alwaysRaised:是否顯示在所有窗口的頂部。
  • alwaysLowered:是否顯示在父窗口的底下。
  • close:新窗口是否顯示關(guān)閉按鈕。

對于那些可以打開和關(guān)閉的屬性,設(shè)為yes1或不設(shè)任何值就表示打開,比如status=yesstatus=1、status都會得到同樣的結(jié)果。如果想設(shè)為關(guān)閉,不用寫no,而是直接省略這個屬性即可。也就是說,如果在第三個參數(shù)中設(shè)置了一部分屬性,其他沒有被設(shè)置的yes/no屬性都會被設(shè)成no,只有titlebar和關(guān)閉按鈕除外(它們的值默認(rèn)為yes)。

上面這些屬性,屬性名與屬性值之間用等號連接,屬性與屬性之間用逗號分隔。

'height=200,width=200,location=no,status=yes,resizable=yes,scrollbars=yes'

另外,open()方法的第二個參數(shù)雖然可以指定已經(jīng)存在的窗口,但是不等于可以任意控制其他窗口。為了防止被不相干的窗口控制,瀏覽器只有在兩個窗口同源,或者目標(biāo)窗口被當(dāng)前網(wǎng)頁打開的情況下,才允許open方法指向該窗口。

window.open方法返回新窗口的引用。

var windowB = window.open('windowB.html', 'WindowB');
windowB.window.name // "WindowB"

注意,如果新窗口和父窗口不是同源的(即不在同一個域),它們彼此不能獲取對方窗口對象的內(nèi)部屬性。

下面是另一個例子。

var w = window.open();
console.log('已經(jīng)打開新窗口');
w.location = 'http://example.com';

上面代碼先打開一個新窗口,然后在該窗口彈出一個對話框,再將網(wǎng)址導(dǎo)向example.com。

由于open這個方法很容易被濫用,許多瀏覽器默認(rèn)都不允許腳本自動新建窗口。只允許在用戶點擊鏈接或按鈕時,腳本做出反應(yīng),彈出新窗口。因此,有必要檢查一下打開新窗口是否成功。

var popup = window.open();
if (popup === null) {
  // 新建窗口失敗
}

(2)window.close()

window.close方法用于關(guān)閉當(dāng)前窗口,一般只用來關(guān)閉window.open方法新建的窗口。

popup.close()

該方法只對頂層窗口有效,iframe框架之中的窗口使用該方法無效。

(3)window.stop()

window.stop()方法完全等同于單擊瀏覽器的停止按鈕,會停止加載圖像、視頻等正在或等待加載的對象。

window.stop()

window.moveTo(),window.moveBy() 

window.moveTo()方法用于移動瀏覽器窗口到指定位置。它接受兩個參數(shù),分別是窗口左上角距離屏幕左上角的水平距離和垂直距離,單位為像素。

window.moveTo(100, 200)

上面代碼將窗口移動到屏幕(100, 200)的位置。

window.moveBy()方法將窗口移動到一個相對位置。它接受兩個參數(shù),分別是窗口左上角向右移動的水平距離和向下移動的垂直距離,單位為像素。

window.moveBy(25, 50)

上面代碼將窗口向右移動25像素、向下移動50像素。

為了防止有人濫用這兩個方法,隨意移動用戶的窗口,目前只有一種情況,瀏覽器允許用腳本移動窗口:該窗口是用window.open()方法新建的,并且窗口里只有它一個 Tab 頁。除此以外的情況,使用上面兩個方法都是無效的。

window.resizeTo(),window.resizeBy() 

window.resizeTo()方法用于縮放窗口到指定大小。

它接受兩個參數(shù),第一個是縮放后的窗口寬度(outerWidth屬性,包含滾動條、標(biāo)題欄等等),第二個是縮放后的窗口高度(outerHeight屬性)。

window.resizeTo(
  window.screen.availWidth / 2,
  window.screen.availHeight / 2
)

上面代碼將當(dāng)前窗口縮放到,屏幕可用區(qū)域的一半寬度和高度。

window.resizeBy()方法用于縮放窗口。它與window.resizeTo()的區(qū)別是,它按照相對的量縮放,window.resizeTo()需要給出縮放后的絕對大小。

它接受兩個參數(shù),第一個是水平縮放的量,第二個是垂直縮放的量,單位都是像素。

window.resizeBy(-200, -200)

上面的代碼將當(dāng)前窗口的寬度和高度,都縮小200像素。

window.scrollTo(),window.scroll(),window.scrollBy() 

window.scrollTo方法用于將文檔滾動到指定位置。它接受兩個參數(shù),表示滾動后位于窗口左上角的頁面坐標(biāo)。

window.scrollTo(x-coord, y-coord)

它也可以接受一個配置對象作為參數(shù)。

window.scrollTo(options)

配置對象options有三個屬性。

  • top:滾動后頁面左上角的垂直坐標(biāo),即 y 坐標(biāo)。
  • left:滾動后頁面左上角的水平坐標(biāo),即 x 坐標(biāo)。
  • behavior:字符串,表示滾動的方式,有三個可能值(smooth、instantauto),默認(rèn)值為auto
window.scrollTo({
  top: 1000,
  behavior: 'smooth'
});

window.scroll()方法是window.scrollTo()方法的別名。

window.scrollBy()方法用于將網(wǎng)頁滾動指定距離(單位像素)。它接受兩個參數(shù):水平向右滾動的像素,垂直向下滾動的像素。

window.scrollBy(0, window.innerHeight)

上面代碼用于將網(wǎng)頁向下滾動一屏。

如果不是要滾動整個文檔,而是要滾動某個元素,可以使用下面三個屬性和方法。

  • Element.scrollTop
  • Element.scrollLeft
  • Element.scrollIntoView()

window.print() 

window.print方法會跳出打印對話框,與用戶點擊菜單里面的“打印”命令效果相同。

常見的打印按鈕代碼如下。

document.getElementById('printLink').onclick = function () {
  window.print();
}

非桌面設(shè)備(比如手機(jī))可能沒有打印功能,這時可以這樣判斷。

if (typeof window.print === 'function') {
  // 支持打印功能
}

window.focus(),window.blur() 

window.focus()方法會激活窗口,使其獲得焦點,出現(xiàn)在其他窗口的前面。

var popup = window.open('popup.html', 'Popup Window');

if ((popup !== null) && !popup.closed) {
  popup.focus();
}

上面代碼先檢查popup窗口是否依然存在,確認(rèn)后激活該窗口。

window.blur()方法將焦點從窗口移除。

當(dāng)前窗口獲得焦點時,會觸發(fā)focus事件;當(dāng)前窗口失去焦點時,會觸發(fā)blur事件。

window.getSelection() 

window.getSelection方法返回一個Selection對象,表示用戶現(xiàn)在選中的文本。

var selObj = window.getSelection();

使用Selection對象的toString方法可以得到選中的文本。

var selectedText = selObj.toString();

window.getComputedStyle(),window.matchMedia() 

window.getComputedStyle()方法接受一個元素節(jié)點作為參數(shù),返回一個包含該元素的最終樣式信息的對象,詳見《CSS 操作》一章。

window.matchMedia()方法用來檢查 CSS 的mediaQuery語句,詳見《CSS 操作》一章。

window.requestAnimationFrame() 

window.requestAnimationFrame()方法跟setTimeout類似,都是推遲某個函數(shù)的執(zhí)行。不同之處在于,setTimeout必須指定推遲的時間,window.requestAnimationFrame()則是推遲到瀏覽器下一次重流時執(zhí)行,執(zhí)行完才會進(jìn)行下一次重繪。重繪通常是 16ms 執(zhí)行一次,不過瀏覽器會自動調(diào)節(jié)這個速率,比如網(wǎng)頁切換到后臺 Tab 頁時,requestAnimationFrame()會暫停執(zhí)行。

如果某個函數(shù)會改變網(wǎng)頁的布局,一般就放在window.requestAnimationFrame()里面執(zhí)行,這樣可以節(jié)省系統(tǒng)資源,使得網(wǎng)頁效果更加平滑。因為慢速設(shè)備會用較慢的速率重流和重繪,而速度更快的設(shè)備會有更快的速率。

該方法接受一個回調(diào)函數(shù)作為參數(shù)。

window.requestAnimationFrame(callback)

上面代碼中,callback是一個回調(diào)函數(shù)。callback執(zhí)行時,它的參數(shù)就是系統(tǒng)傳入的一個高精度時間戳(performance.now()的返回值),單位是毫秒,表示距離網(wǎng)頁加載的時間。

window.requestAnimationFrame()的返回值是一個整數(shù),這個整數(shù)可以傳入window.cancelAnimationFrame(),用來取消回調(diào)函數(shù)的執(zhí)行。

下面是一個window.requestAnimationFrame()執(zhí)行網(wǎng)頁動畫的例子。

var element = document.getElementById('animate');
element.style.position = 'absolute';

var start = null;

function step(timestamp) {
  if (!start) start = timestamp;
  var progress = timestamp - start;
  // 元素不斷向左移,最大不超過200像素
  element.style.left = Math.min(progress / 10, 200) + 'px';
  // 如果距離第一次執(zhí)行不超過 2000 毫秒,
  // 就繼續(xù)執(zhí)行動畫
  if (progress < 2000) {
    window.requestAnimationFrame(step);
  }
}

window.requestAnimationFrame(step);

上面代碼定義了一個網(wǎng)頁動畫,持續(xù)時間是2秒,會讓元素向右移動。

window.requestIdleCallback() 

window.requestIdleCallback()setTimeout類似,也是將某個函數(shù)推遲執(zhí)行,但是它保證將回調(diào)函數(shù)推遲到系統(tǒng)資源空閑時執(zhí)行。也就是說,如果某個任務(wù)不是很關(guān)鍵,就可以使用window.requestIdleCallback()將其推遲執(zhí)行,以保證網(wǎng)頁性能。

它跟window.requestAnimationFrame()的區(qū)別在于,后者指定回調(diào)函數(shù)在下一次瀏覽器重排時執(zhí)行,問題在于下一次重排時,系統(tǒng)資源未必空閑,不一定能保證在16毫秒之內(nèi)完成;window.requestIdleCallback()可以保證回調(diào)函數(shù)在系統(tǒng)資源空閑時執(zhí)行。

該方法接受一個回調(diào)函數(shù)和一個配置對象作為參數(shù)。配置對象可以指定一個推遲執(zhí)行的最長時間,如果過了這個時間,回調(diào)函數(shù)不管系統(tǒng)資源有無空閑,都會執(zhí)行。

window.requestIdleCallback(callback[, options])

callback參數(shù)是一個回調(diào)函數(shù)。該回調(diào)函數(shù)執(zhí)行時,系統(tǒng)會傳入一個IdleDeadline對象作為參數(shù)。IdleDeadline對象有一個didTimeout屬性(布爾值,表示是否為超時調(diào)用)和一個timeRemaining()方法(返回該空閑時段剩余的毫秒數(shù))。

options參數(shù)是一個配置對象,目前只有timeout一個屬性,用來指定回調(diào)函數(shù)推遲執(zhí)行的最大毫秒數(shù)。該參數(shù)可選。

window.requestIdleCallback()方法返回一個整數(shù)。該整數(shù)可以傳入window.cancelIdleCallback()取消回調(diào)函數(shù)。

下面是一個例子。

requestIdleCallback(myNonEssentialWork);

function myNonEssentialWork(deadline) {
  while (deadline.timeRemaining() > 0) {
    doWorkIfNeeded();
  }
}

上面代碼中,requestIdleCallback()用來執(zhí)行非關(guān)鍵任務(wù)myNonEssentialWork。該任務(wù)先確認(rèn)本次空閑時段有剩余時間,然后才真正開始執(zhí)行任務(wù)。

下面是指定timeout的例子。

requestIdleCallback(processPendingAnalyticsEvents, { timeout: 2000 });

上面代碼指定,processPendingAnalyticsEvents必須在未來2秒之內(nèi)執(zhí)行。

如果由于超時導(dǎo)致回調(diào)函數(shù)執(zhí)行,則deadline.timeRemaining()返回0,deadline.didTimeout返回true

如果多次執(zhí)行window.requestIdleCallback(),指定多個回調(diào)函數(shù),那么這些回調(diào)函數(shù)將排成一個隊列,按照先進(jìn)先出的順序執(zhí)行。

事件 

window對象可以接收以下事件。

load 事件和 onload 屬性 

load事件發(fā)生在文檔在瀏覽器窗口加載完畢時。window.onload屬性可以指定這個事件的回調(diào)函數(shù)。

window.onload = function() {
  var elements = document.getElementsByClassName('example');
  for (var i = 0; i < elements.length; i++) {
    var elt = elements[i];
    // ...
  }
};

上面代碼在網(wǎng)頁加載完畢后,獲取指定元素并進(jìn)行處理。

error 事件和 onerror 屬性 

瀏覽器腳本發(fā)生錯誤時,會觸發(fā)window對象的error事件。我們可以通過window.onerror屬性對該事件指定回調(diào)函數(shù)。

window.onerror = function (message, filename, lineno, colno, error) {
  console.log("出錯了!--> %s", error.stack);
};

由于歷史原因,windowerror事件的回調(diào)函數(shù)不接受錯誤對象作為參數(shù),而是一共可以接受五個參數(shù),它們的含義依次如下。

  • 出錯信息
  • 出錯腳本的網(wǎng)址
  • 行號
  • 列號
  • 錯誤對象

老式瀏覽器只支持前三個參數(shù)。

并不是所有的錯誤,都會觸發(fā) JavaScript 的error事件(即讓 JavaScript 報錯)。一般來說,只有 JavaScript 腳本的錯誤,才會觸發(fā)這個事件,而像資源文件不存在之類的錯誤,都不會觸發(fā)。

下面是一個例子,如果整個頁面未捕獲錯誤超過3個,就顯示警告。

window.onerror = function(msg, url, line) {
  if (onerror.num++ > onerror.max) {
    alert('ERROR: ' + msg + '\n' + url + ':' + line);
    return true;
  }
}
onerror.max = 3;
onerror.num = 0;

需要注意的是,如果腳本網(wǎng)址與網(wǎng)頁網(wǎng)址不在同一個域(比如使用了 CDN),瀏覽器根本不會提供詳細(xì)的出錯信息,只會提示出錯,錯誤類型是“Script error.”,行號為0,其他信息都沒有。這是瀏覽器防止向外部腳本泄漏信息。一個解決方法是在腳本所在的服務(wù)器,設(shè)置Access-Control-Allow-Origin的 HTTP 頭信息。

Access-Control-Allow-Origin: *

然后,在網(wǎng)頁的<script>標(biāo)簽中設(shè)置crossorigin屬性。

<script crossorigin="anonymous" src="http://example.com/file.js" rel="external nofollow" ></script>

上面代碼的crossorigin="anonymous"表示,讀取文件不需要身份信息,即不需要 cookie 和 HTTP 認(rèn)證信息。如果設(shè)為crossorigin="use-credentials",就表示瀏覽器會上傳 cookie 和 HTTP 認(rèn)證信息,同時還需要服務(wù)器端打開 HTTP 頭信息Access-Control-Allow-Credentials。

window 對象的事件監(jiān)聽屬性 

除了具備元素節(jié)點都有的 GlobalEventHandlers 接口,window對象還具有以下的事件監(jiān)聽函數(shù)屬性。

  • window.onafterprintafterprint事件的監(jiān)聽函數(shù)。
  • window.onbeforeprintbeforeprint事件的監(jiān)聽函數(shù)。
  • window.onbeforeunloadbeforeunload事件的監(jiān)聽函數(shù)。
  • window.onhashchangehashchange事件的監(jiān)聽函數(shù)。
  • window.onlanguagechange: languagechange的監(jiān)聽函數(shù)。
  • window.onmessagemessage事件的監(jiān)聽函數(shù)。
  • window.onmessageerrorMessageError事件的監(jiān)聽函數(shù)。
  • window.onofflineoffline事件的監(jiān)聽函數(shù)。
  • window.ononlineonline事件的監(jiān)聽函數(shù)。
  • window.onpagehidepagehide事件的監(jiān)聽函數(shù)。
  • window.onpageshowpageshow事件的監(jiān)聽函數(shù)。
  • window.onpopstatepopstate事件的監(jiān)聽函數(shù)。
  • window.onstoragestorage事件的監(jiān)聽函數(shù)。
  • window.onunhandledrejection:未處理的 Promise 對象的reject事件的監(jiān)聽函數(shù)。
  • window.onunloadunload事件的監(jiān)聽函數(shù)。

多窗口操作 

由于網(wǎng)頁可以使用iframe元素,嵌入其他網(wǎng)頁,因此一個網(wǎng)頁之中會形成多個窗口。如果子窗口之中又嵌入別的網(wǎng)頁,就會形成多級窗口。

窗口的引用 

各個窗口之中的腳本,可以引用其他窗口。瀏覽器提供了一些特殊變量,用來返回其他窗口。

  • top:頂層窗口,即最上層的那個窗口
  • parent:父窗口
  • self:當(dāng)前窗口,即自身

下面代碼可以判斷,當(dāng)前窗口是否為頂層窗口。

if (window.top === window.self) {
  // 當(dāng)前窗口是頂層窗口
} else {
  // 當(dāng)前窗口是子窗口
}

下面的代碼讓父窗口的訪問歷史后退一次。

window.parent.history.back();

與這些變量對應(yīng),瀏覽器還提供一些特殊的窗口名,供window.open()方法、<a>標(biāo)簽、<form>標(biāo)簽等引用。

  • _top:頂層窗口
  • _parent:父窗口
  • _blank:新窗口

下面代碼就表示在頂層窗口打開鏈接。

<a href="somepage.html" target="_top">Link</a>

iframe 元素 

對于iframe嵌入的窗口,document.getElementById方法可以拿到該窗口的 DOM 節(jié)點,然后使用contentWindow屬性獲得iframe節(jié)點包含的window對象。

var frame = document.getElementById('theFrame');
var frameWindow = frame.contentWindow;

上面代碼中,frame.contentWindow可以拿到子窗口的window對象。然后,在滿足同源限制的情況下,可以讀取子窗口內(nèi)部的屬性。

// 獲取子窗口的標(biāo)題
frameWindow.title

<iframe>元素的contentDocument屬性,可以拿到子窗口的document對象。

var frame = document.getElementById('theFrame');
var frameDoc = frame.contentDocument;

// 等同于
var frameDoc = frame.contentWindow.document;

<iframe>元素遵守同源政策,只有當(dāng)父窗口與子窗口在同一個域時,兩者之間才可以用腳本通信,否則只有使用window.postMessage方法。

<iframe>窗口內(nèi)部,使用window.parent引用父窗口。如果當(dāng)前頁面沒有父窗口,則window.parent屬性返回自身。因此,可以通過window.parent是否等于window.self,判斷當(dāng)前窗口是否為iframe窗口。

if (window.parent !== window.self) {
  // 當(dāng)前窗口是子窗口
}

<iframe>窗口的window對象,有一個frameElement屬性,返回<iframe>在父窗口中的 DOM 節(jié)點。對于非嵌入的窗口,該屬性等于null。

var f1Element = document.getElementById('f1');
var f1Window = f1Element.contentWindow;

f1Window.frameElement === f1Element // true
window.frameElement === null // true

window.frames 屬性 

window.frames屬性返回一個類似數(shù)組的對象,成員是所有子窗口的window對象??梢允褂眠@個屬性,實現(xiàn)窗口之間的互相引用。比如,frames[0]返回第一個子窗口,frames[1].frames[2]返回第二個子窗口內(nèi)部的第三個子窗口,parent.frames[1]返回父窗口的第二個子窗口。

注意,window.frames每個成員的值,是框架內(nèi)的窗口(即框架的window對象),而不是iframe標(biāo)簽在父窗口的 DOM 節(jié)點。如果要獲取每個框架內(nèi)部的 DOM 樹,需要使用window.frames[0].document的寫法。

另外,如果<iframe>元素設(shè)置了nameid屬性,那么屬性值會自動成為全局變量,并且可以通過window.frames屬性引用,返回子窗口的window對象。

// HTML 代碼為 <iframe id="myFrame">
window.myFrame // [HTMLIFrameElement]
frames.myframe === myFrame // true

另外,name屬性的值會自動成為子窗口的名稱,可以用在window.open方法的第二個參數(shù),或者<a><frame>標(biāo)簽的target屬性。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號