主頁 > 前端設計 > JavaScript(六)(瀏覽器模型/window物件)

JavaScript(六)(瀏覽器模型/window物件)

2021-07-30 07:57:29 前端設計

JavaScript(六)(瀏覽器模型/window物件)

文章目錄

  • JavaScript(六)(瀏覽器模型/window物件)
  • 八、瀏覽器模型
    • 54. 瀏覽器環境概述
      • 54.1 代碼嵌入網頁的方法
        • 54.1.1 script 元素嵌入代碼
        • 54.1.2 script 元素加載外部腳本
        • 54.1.3 事件屬性
        • 54.1.4 URL 協議
      • 54.2 script 元素
        • ==54.2.1 網頁作業原理==
        • 54.2.2 defer 屬性
        • 54.2.3 async 屬性
        • 54.2.4 腳本的動態加載
      • 54.3 瀏覽器的組成
        • 54.3.1 渲染引擎
        • 54.3.2 重流和重繪(==`window.requestAnimationFrame()`==)
        • 54.3.3 ==window.requestAnimationFrame==(==52.4.1 scroll 事件(throttle節流)== 55.3.10)
          • (1)語法
          • (2)引數
          • (3)回傳值
          • (4)范例
        • 54.3.4 JavaScript 引擎
    • 55. window 物件
      • 55.1 概述
      • 55.2 window 物件的屬性
        • 55.2.1 window.name
        • 55.2.2 window.closed,window.opener
        • 55.2.3 window.self,window.window
        • 55.2.4 window.frames,window.length
        • 55.2.5 window.frameElement
        • 55.2.6 window.top,window.parent
        • 55.2.7 window.status
        • 55.2.8 window.devicePixelRatio
        • 55.2.9 位置大小屬性
          • **(1)window.screenX,window.screenY**
          • **(2) window.innerHeight,window.innerWidth**
          • **(3)window.outerHeight,window.outerWidth**
          • **(4)window.scrollX,window.scrollY**
          • **(5)window.pageXOffset,window.pageYOffset**
        • 55.2.10 組件屬性
        • 55.2.11 全域物件屬性
        • 55.2.12 window.isSecureContext
      • 55.3 window 物件的方法
        • 55.3.1 window.alert(),window.prompt(),window.confirm()
          • **(1)window.alert()**
          • **(2)window.prompt()**
          • **(3)window.confirm()**
        • 55.3.2 window.open(), window.close(),window.stop()
          • **(1)window.open()**
          • **(2)window.close()**
          • **(3)window.stop()**
        • 55.3.3 window.moveTo(),window.moveBy()
        • 55.3.4 window.resizeTo(),window.resizeBy()
        • 55.3.5 window.scrollTo(),window.scroll(),window.scrollBy()
        • 55.3.6 window.print()
        • 55.3.7 window.focus(),window.blur()
        • 55.3.8 window.getSelection()
        • 55.3.9 window.getComputedStyle(),window.matchMedia()
        • ==55.3.10 window.requestAnimationFrame()(54.3.3)==
        • ==55.3.11 window.requestIdleCallback()==
      • 55.4 事件
        • 55.4.1 load 事件和 onl oad 屬性
        • 55.4.2 error 事件和 one rror 屬性
        • 55.4.3 window 物件的事件監聽屬性
      • 55.5 多視窗操作
        • 55.5.1 視窗的參考
        • 55.5.2 iframe 元素
        • 55.5.3 window.frames 屬性

八、瀏覽器模型

54. 瀏覽器環境概述

JavaScript 是瀏覽器的內置腳本語言,也就是說,瀏覽器內置了 JavaScript 引擎,并且提供各種介面,讓 JavaScript 腳本可以控制瀏覽器的各種功能,一旦網頁內嵌了 JavaScript 腳本,瀏覽器加載網頁,就會去執行腳本,從而達到操作瀏覽器的目的,實作網頁的各種動態效果,

本章開始介紹瀏覽器提供的各種 JavaScript 介面,首先,介紹 JavaScript 代碼嵌入網頁的方法,

54.1 代碼嵌入網頁的方法

網頁中嵌入 JavaScript 代碼,主要有四種方法,

  • <script>元素直接嵌入代碼,
  • <script>標簽加載外部腳本
  • 事件屬性
  • URL 協議

54.1.1 script 元素嵌入代碼


<script>標簽有一個type屬性,用來指定腳本型別,對 JavaScript 腳本來說,type屬性可以設為兩種值,

- `text/javascript`:這是默認值,也是歷史上一貫設定的值,如果你省略`type`屬性,默認就是這個值,對于老式瀏覽器,設為這個值比較好,
- `application/javascript`:對于較新的瀏覽器,建議設為這個值,

```javascript
<script type="application/javascript">
  console.log('Hello World');
</script>

由于<script>標簽默認就是 JavaScript 代碼,所以,嵌入 JavaScript 腳本時,type屬性可以省略,

如果type屬性的值,瀏覽器不認識,那么它不會執行其中的代碼,利用這一點,可以在<script>標簽之中嵌入任意的文本內容,只要加上一個瀏覽器不認識的type屬性即可,

<script id="mydata" type="x-custom-data">
  console.log('Hello World');
</script>

上面的代碼,瀏覽器不會執行,也不會顯示它的內容,因為不認識它的type屬性,但是,這個<script>節點依然存在于 DOM 之中,可以使用<script>節點的text屬性讀出它的內容,

document.getElementById('mydata').text
//   console.log('Hello World');

54.1.2 script 元素加載外部腳本


如果腳本檔案使用了非英語字符,還應該注明字符的編碼,

```javascript
<script charset="utf-8" src="https://www.example.com/script.js"></script>

所加載的腳本必須是純的 JavaScript 代碼,不能有HTML代碼和<script>標簽,

加載外部腳本和直接添加代碼塊,這兩種方法不能混用,下面代碼的console.log陳述句直接被忽略,

<script charset="utf-8" src="example.js">
  console.log('Hello World!');
</script>

為了防止攻擊者篡改外部腳本,script標簽允許設定一個integrity屬性,寫入該外部腳本的 Hash 簽名,用來驗證腳本的一致性,

<script src="/assets/application.js"
  integrity="sha256-TvVUHzSfftWg1rcfL6TIJ0XKEGrgLyEq6lEpcmrG9qs=">
</script>

上面代碼中,script標簽有一個integrity屬性,指定了外部腳本/assets/application.js的 SHA256 簽名,一旦有人改了這個腳本,導致 SHA256 簽名不匹配,瀏覽器就會拒絕加載,

54.1.3 事件屬性

網頁元素的事件屬性(比如onclickonmouseover),可以寫入 JavaScript 代碼,當指定事件發生時,就會呼叫這些代碼,

<button id="myBtn" onclick="console.log(this.id)">點擊</button>

上面的事件屬性代碼只有一個陳述句,如果有多個陳述句,使用分號分隔即可,

54.1.4 URL 協議

URL 支持javascript:協議,即在 URL 的位置寫入代碼,使用這個 URL 的時候就會執行 JavaScript 代碼,

<a href="javascript:console.log('Hello')">點擊</a>

瀏覽器的地址欄也可以執行javascript:協議,將javascript:console.log('Hello')放入地址欄,按回車鍵也會執行這段代碼,

如果 JavaScript 代碼回傳一個字串,瀏覽器就會新建一個檔案,展示這個字串的內容,原有檔案的內容都會消失,

<a href="javascript: new Date().toLocaleTimeString();">點擊</a>

上面代碼中,用戶點擊鏈接以后,會打開一個新檔案,里面有當前時間,

如果回傳的不是字串,那么瀏覽器不會新建檔案,也不會跳轉,

<a href="javascript: console.log(new Date().toLocaleTimeString())">點擊</a>

上面代碼中,用戶點擊鏈接后,網頁不會跳轉,只會在控制臺顯示當前時間,

javascript:協議的常見用途是書簽腳本 Bookmarklet,由于瀏覽器的書簽保存的是一個網址,所以javascript:網址也可以保存在里面,用戶選擇這個書簽的時候,就會在當前頁面執行這個腳本,為了防止書簽替換掉當前檔案,可以在腳本前加上void,或者在腳本最后加上void 0

<a href="javascript: void new Date().toLocaleTimeString();">點擊</a>
<a href="javascript: new Date().toLocaleTimeString();void 0;">點擊</a>

上面這兩種寫法,點擊鏈接后,執行代碼都不會網頁跳轉,

54.2 script 元素

54.2.1 網頁作業原理

瀏覽器加載 JavaScript 腳本,主要通過<script>元素完成,正常的網頁加載流程是這樣的,

  1. 瀏覽器一邊下載 HTML 網頁,一邊開始決議,也就是說,不等到下載完,就開始決議,
  2. 決議程序中,瀏覽器發現<script>元素,就暫停決議,把網頁渲染的控制權轉交給 JavaScript 引擎,
  3. 如果<script>元素參考了外部腳本,就下載該腳本再執行,否則就直接執行代碼,
  4. JavaScript 引擎執行完畢,控制權交還渲染引擎,恢復往下決議 HTML 網頁,

加載外部腳本時,瀏覽器會暫停頁面渲染,等待腳本下載并執行完成后,再繼續渲染原因是 JavaScript 代碼可以修改 DOM,所以必須把控制權讓給它,否則會導致復雜的執行緒競賽的問題,

如果外部腳本加載時間很長(一直無法完成下載),那么瀏覽器就會一直等待腳本下載完成,造成網頁長時間失去回應,瀏覽器就會呈現“假死”狀態,這被稱為==“阻塞效應”==,

為了避免這種情況,較好的做法是將<script>標簽都放在頁面底部,而不是頭部,這樣即使遇到腳本失去回應,網頁主體的渲染也已經完成了,用戶至少可以看到內容,而不是面對一張空白的頁面,如果某些腳本代碼非常重要,一定要放在頁面頭部的話,最好直接將代碼寫入頁面,而不是連接外部腳本檔案,這樣能縮短加載時間,

腳本檔案都放在網頁尾部加載,還有一個好處,因為在 DOM 結構生成之前就呼叫 DOM 節點,JavaScript 會報錯,如果腳本都在網頁尾部加載,就不存在這個問題,因為這時 DOM 肯定已經生成了,

<head>
  <script>
    console.log(document.body.innerHTML);
  </script>
</head>
<body>
</body>

上面代碼執行時會報錯,因為此時document.body元素還未生成,

一種解決方法是設定DOMContentLoaded事件的回呼函式,

<head>
  <script>
    document.addEventListener(
      'DOMContentLoaded',
      function (event) {
        console.log(document.body.innerHTML);
      }
    );
  </script>
</head>

上面代碼中,指定DOMContentLoaded事件發生后,才開始執行相關代碼,DOMContentLoaded事件只有在 DOM 結構生成之后才會觸發,

另一種解決方法是,使用<script>標簽的onload屬性,當<script>標簽指定的外部腳本檔案下載和決議完成,會觸發一個load事件,可以把所需執行的代碼,放在這個事件的回呼函式里面,

<script src="jquery.min.js" onl oad="console.log(document.body.innerHTML)">
</script>

但是,如果將腳本放在頁面底部,就可以完全按照正常的方式寫,上面兩種方式都不需要

<body>
  <!-- 其他代碼  -->
  <script>
    console.log(document.body.innerHTML);
  </script>
</body>

如果有多個script標簽,比如下面這樣,

<script src="a.js"></script>
<script src="b.js"></script>

瀏覽器會同時并行下載a.jsb.js,但是,執行時會保證先執行a.js,然后再執行b.js,即使后者先下載完成,也是如此,也就是說,腳本的執行順序由它們在頁面中的出現順序決定,這是為了保證腳本之間的依賴關系不受到破壞,當然,加載這兩個腳本都會產生“阻塞效應”,必須等到它們都加載完成,瀏覽器才會繼續頁面渲染,

**決議和執行 CSS,也會產生阻塞,**Firefox 瀏覽器會等到腳本前面的所有樣式表,都下載并決議完,再執行腳本;Webkit則是一旦發現腳本參考了樣式,就會暫停執行腳本,等到樣式表下載并決議完,再恢復執行,

此外,對于來自同一個域名的資源,比如腳本檔案、樣式表檔案、圖片檔案等,瀏覽器一般有限制,同時最多下載6~20個資源,即最多同時打開的 TCP 連接有限制,這是為了防止對服務器造成太大壓力,如果是來自不同域名的資源,就沒有這個限制,所以,通常把靜態檔案放在不同的域名之下,以加快下載速度

54.2.2 defer 屬性

為了解決腳本檔案下載阻塞網頁渲染的問題,一個方法是對<script>元素加入defer屬性,它的作用是延遲腳本的執行,等到 DOM 加載生成后,再執行腳本,

<script src="a.js" defer></script>
<script src="b.js" defer></script>

上面代碼中,只有等到 DOM 加載完成后,才會執行a.jsb.js

defer屬性的運行流程如下,(先下載,后執行

  1. 瀏覽器開始決議 HTML 網頁,
  2. 決議程序中,發現帶有defer屬性的<script>元素,
  3. 瀏覽器繼續往下決議 HTML 網頁,同時并行下載<script>元素加載的外部腳本
  4. 瀏覽器完成決議 HTML 網頁,此時再回過頭執行已經下載完成的腳本

有了defer屬性,瀏覽器下載腳本檔案的時候,不會阻塞頁面渲染,下載的腳本檔案在DOMContentLoaded事件觸發前執行(即剛剛讀取完</html>標簽),而且可以保證執行順序就是它們在頁面上出現的順序,

對于內置而不是加載外部腳本的script標簽,以及動態生成的script標簽,defer屬性不起作用,另外,使用defer加載的外部腳本不應該使用document.write方法,

54.2.3 async 屬性

解決“阻塞效應”的另一個方法是對<script>元素加入async屬性,

<script src="a.js" async></script>
<script src="b.js" async></script>

async屬性的作用是,使用另一個行程下載腳本,下載時不會阻塞渲染,也是先下載,再執行,但會暫停決議HTML網頁,并且無法確定執行順序

  1. 瀏覽器開始決議 HTML 網頁,
  2. 決議程序中,發現帶有async屬性的script標簽,
  3. 瀏覽器繼續往下決議 HTML 網頁,同時并行下載<script>標簽中的外部腳本,
  4. 腳本下載完成,瀏覽器暫停決議 HTML 網頁,開始執行下載的腳本,
  5. 腳本執行完畢,瀏覽器恢復決議 HTML 網頁,

async屬性可以保證腳本下載的同時,瀏覽器繼續渲染,需要注意的是,==一旦采用這個屬性,就無法保證腳本的執行順序,哪個腳本先下載結束,就先執行那個腳本,==另外,使用async屬性的腳本檔案里面的代碼,不應該使用document.write方法,

defer屬性和async屬性到底應該使用哪一個?

一般來說,如果腳本之間沒有依賴關系,就使用async屬性,如果腳本之間有依賴關系,就使用defer屬性,如果同時使用asyncdefer屬性,后者不起作用,瀏覽器行為由async屬性決定,

54.2.4 腳本的動態加載


上面的`example.js`默認就是采用 HTTP 協議下載,如果要采用 HTTPS 協議下載,必需寫明,

```javascript
<script src="https://example.js"></script>

但是有時我們會希望,根據頁面本身的協議來決定加載協議,這時可以采用下面的寫法,

<script src="//example.js"></script>

54.3 瀏覽器的組成

瀏覽器的核心是兩部分:渲染引擎和 JavaScript 解釋器(又稱 JavaScript 引擎),

54.3.1 渲染引擎

渲染引擎的主要作用是,將網頁代碼渲染為用戶視覺可以感知的平面檔案,

不同的瀏覽器有不同的渲染引擎,

  • Firefox:Gecko 引擎
  • Safari:WebKit 引擎
  • Chrome:Blink 引擎
  • IE: Trident 引擎
  • Edge: EdgeHTML 引擎

渲染引擎處理網頁,通常分成四個階段,

  1. 決議代碼:HTML 代碼決議為 DOM,CSS 代碼決議為 CSSOM(CSS Object Model),
  2. 物件合成:將 DOM 和 CSSOM 合成一棵渲染樹(render tree),
  3. 布局:計算出渲染樹的布局(layout),
  4. 繪制:將渲染樹繪制到螢屏,

以上四步并非嚴格按順序執行,往往第一步還沒完成,第二步和第三步就已經開始了,所以,會看到這種情況:網頁的 HTML 代碼還沒下載完,但瀏覽器已經顯示出內容了,

54.3.2 重流和重繪(window.requestAnimationFrame()

渲染樹轉換為網頁布局,稱為“布局流”(flow);布局顯示到頁面的這個程序,稱為“繪制”(paint),它們都具有阻塞效應,并且會耗費很多時間和計算資源,

頁面生成以后,腳本操作和樣式表操作,都會觸發“重流”(reflow)和“重繪”(repaint),用戶的互動也會觸發重流和重繪,比如設定了滑鼠懸停(a:hover)效果、頁面滾動、在輸入框中輸入文本、改變視窗大小等等,

重流和重繪并不一定一起發生,重流必然導致重繪,重繪不一定需要重流,比如改變元素顏色,只會導致重繪,而不會導致重流;改變元素的布局,則會導致重繪和重流,

大多數情況下,瀏覽器會智能判斷,將重流和重繪只限制到相關的子樹上面,最小化所耗費的代價,而不會全域重新生成網頁,

作為開發者,應該盡量設法降低重繪的次數和成本,比如,盡量不要變動高層的 DOM 元素,而以底層 DOM 元素的變動代替;再比如,重繪table布局和flex布局,開銷都會比較大,

var foo = document.getElementById('foobar');

foo.style.color = 'blue';
foo.style.marginTop = '30px';

上面的代碼只會導致一次重繪,因為瀏覽器會累積 DOM 變動,然后一次性執行,

下面是一些優化技巧

  • 讀取 DOM 或者寫入 DOM,盡量寫在一起,不要混雜,不要讀取一個 DOM 節點,然后立刻寫入,接著再讀取一個 DOM 節點,
  • 快取 DOM 資訊,
  • 不要一項一項地改變樣式,而是使用 CSS class 一次性改變樣式,
  • 使用documentFragment操作 DOM
  • 影片使用absolute定位或fixed定位,這樣可以減少對其他元素的影響,
  • 只在必要時才顯示隱藏元素,
  • 使用window.requestAnimationFrame(),因為它可以把代碼推遲到下一次重繪之前執行,而不是立即要求頁面重繪,
  • 使用虛擬 DOM(virtual DOM)庫,

下面是一個window.requestAnimationFrame()對比效果的例子,

// 重流代價高
function doubleHeight(element) {
  var currentHeight = element.clientHeight;
  element.style.height = (currentHeight * 2) + 'px';
}

all_my_elements.forEach(doubleHeight);

// 重繪代價低
function doubleHeight(element) {
  var currentHeight = element.clientHeight;

  window.requestAnimationFrame(function () {
    element.style.height = (currentHeight * 2) + 'px';
  });
}

all_my_elements.forEach(doubleHeight);

上面的第一段代碼,每讀一次 DOM,就寫入新的值,會造成不停的重排和重流,第二段代碼把所有的寫操作,都累積在一起,從而 DOM 代碼變動的代價就最小化了,

54.3.3 window.requestAnimationFrame52.4.1 scroll 事件(throttle節流) 55.3.10)

window.requestAnimationFrame() 告訴瀏覽器——你希望執行一個影片,并且要求瀏覽器在下次重繪之前呼叫指定的回呼函式更新影片,該方法需要傳入一個回呼函式作為引數,該回呼函式會在瀏覽器下一次重繪之前執行

注意:若你想在瀏覽器下次重繪之前繼續更新下一幀影片,那么回呼函式自身必須再次呼叫window.requestAnimationFrame()

當你準備更新影片時你應該呼叫此方法,這將使瀏覽器在下一次重繪之前呼叫你傳入給該方法的影片函式(即你的回呼函式),回呼函式執行次數通常是每秒60次,但在大多數遵循W3C建議的瀏覽器中,回呼函式執行次數通常與瀏覽器螢屏重繪次數相匹配,為了提高性能和電池壽命,因此在大多數瀏覽器里,當requestAnimationFrame() 運行在后臺標簽頁或者隱藏的iframe 里時,requestAnimationFrame() 會被暫停呼叫以提升性能和電池壽命,

回呼函式會被傳入DOMHighResTimeStamp引數,DOMHighResTimeStamp指示當前被 requestAnimationFrame() 排序的回呼函式被觸發的時間,在同一個幀中的多個回呼函式,它們每一個都會接受到一個相同的時間戳,即使在計算上一個回呼函式的作業負載期間已經消耗了一些時間,該時間戳是一個十進制數,單位毫秒,最小精度為1ms(1000μs),

請確保總是使用第一個引數(或其它獲得當前時間的方法)計算每次呼叫之間的時間間隔,否則影片在高重繪率的螢屏中會運行得更快,請參考下面例子的做法,

(1)語法
window.requestAnimationFrame(callback);
(2)引數
  • callback

    下一次重繪之前更新影片幀所呼叫的函式(即上面所說的回呼函式),該回呼函式會被傳入DOMHighResTimeStamp引數,該引數與performance.now()的回傳值相同,它表示requestAnimationFrame() 開始去執行回呼函式的時刻,

(3)回傳值

一個 long 整數,請求 ID ,是回呼串列中唯一的標識,是個非零值,沒別的意義,你可以傳這個值給 window.cancelAnimationFrame() 以取消回呼函式,

(4)范例
const element = document.getElementById('some-element-you-want-to-animate');
let start;

function step(timestamp) {
  if (start === undefined)
    start = timestamp;
  const elapsed = timestamp - start;

  //這里使用`Math.min()`確保元素剛好停在200px的位置,
  element.style.transform = 'translateX(' + Math.min(0.1 * elapsed, 200) + 'px)';

  if (elapsed < 2000) { // 在兩秒后停止影片
    window.requestAnimationFrame(step);
  }
}

window.requestAnimationFrame(step);

54.3.4 JavaScript 引擎

JavaScript 引擎的主要作用是,讀取網頁中的 JavaScript 代碼,對其處理后運行,

JavaScript 是一種解釋型語言,也就是說,它不需要編譯,由解釋器實時運行,這樣的好處是運行和修改都比較方便,重繪頁面就可以重新解釋缺點是每次運行都要呼叫解釋器,系統開銷較大,運行速度慢于編譯型語言,

為了提高運行速度,目前的瀏覽器都將 JavaScript 進行一定程度的編譯,生成類似位元組碼(bytecode)的中間代碼,以提高運行速度,

早期,瀏覽器內部對 JavaScript 的處理程序如下:

  1. 讀取代碼,進行詞法分析(Lexical analysis),將代碼分解成詞元(token),
  2. 對詞元進行語法分析(parsing),將代碼整理成“語法樹”(syntax tree),
  3. 使用“翻譯器”(translator),將代碼轉為位元組碼(bytecode),
  4. 使用“位元組碼解釋器”(bytecode interpreter),將位元組碼轉為機器碼,

逐行解釋將位元組碼轉為機器碼,是很低效的,為了提高運行速度,現代瀏覽器改為采用“即時編譯”(Just In Time compiler,縮寫 JIT),即位元組碼只在運行時編譯,用到哪一行就編譯哪一行,并且把編譯結果快取(inline cache),通常,一個程式被經常用到的,只是其中一小部分代碼,有了快取的編譯結果,整個程式的運行速度就會顯著提升,

位元組碼不能直接運行,而是運行在一個虛擬機(Virtual Machine)之上,一般也把虛擬機稱為 JavaScript 引擎,并非所有的 JavaScript 虛擬機運行時都有位元組碼,有的 JavaScript 虛擬機基于原始碼,即只要有可能,就通過 JIT(just in time)編譯器直接把原始碼編譯成機器碼運行,省略位元組碼步驟,這一點與其他采用虛擬機(比如 Java)的語言不盡相同,這樣做的目的,是為了盡可能地優化代碼、提高性能,下面是目前最常見的一些 JavaScript 虛擬機:

  • Chakra (Microsoft Internet Explorer)
  • Nitro/JavaScript Core (Safari)
  • Carakan (Opera)
  • SpiderMonkey (Firefox)
  • V8 (Chrome, Chromium)

55. window 物件

55.1 概述

瀏覽器里面,window物件(注意,w為小寫)指當前的瀏覽器視窗它也是當前頁面的頂層物件,即最高一層的物件,所有其他物件都是它的下屬一個變數如果未宣告,那么默認就是頂層物件的屬性,

a = 1;
window.a // 1

上面代碼中,a是一個沒有宣告就直接賦值的變數,它自動成為頂層物件的屬性,

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

55.2 window 物件的屬性

55.2.1 window.name

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

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

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

只要瀏覽器視窗不關閉,這個屬性是不會消失的,舉例來說,訪問a.com時,該頁面的腳本設定了window.name,接下來在同一個視窗里面載入了b.com,新頁面的腳本可以讀到上一個網頁設定的window.name,頁面重繪也是這種情況,一旦瀏覽器視窗關閉后,該屬性保存的值就會消失,因為這時視窗已經不存在了,

55.2.2 window.closed,window.opener

window.closed屬性回傳一個布林值,表示視窗是否關閉,

window.closed // false

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

var popup = window.open();

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

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

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

上面運算式會打開一個新視窗,然后回傳true

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

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

上面代碼中,子視窗的opener屬性設為null,兩個視窗之間就沒辦法再聯系了,

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

<a href="https://an.evil.site" target="_blank" rel="noopener">
惡意網站
</a>

55.2.3 window.self,window.window

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

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

55.2.4 window.frames,window.length

window.frames屬性回傳一個類似陣列的物件,成員為頁面內所有框架視窗,包括frame元素和iframe元素,window.frames[0]表示頁面中第一個框架視窗,

如果iframe元素設定了idname屬性,那么就可以用屬性值,參考這個iframe視窗,比如<iframe name="myIFrame">可以用frames['myIFrame']或者frames.myIFrame來參考,

frames屬性實際上是window物件的別名,

frames === window // true

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

window.length屬性回傳當前網頁包含的框架總數,如果當前網頁不包含frameiframe元素,那么window.length就回傳0

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

上面代碼表示,window.frames.lengthwindow.length應該是相等的,

55.2.5 window.frameElement

window.frameElement屬性主要用于當前視窗嵌在另一個網頁的情況(嵌入<object><iframe><embed>元素),回傳當前視窗所在的那個元素節點,如果當前視窗是頂層視窗,或者所嵌入的那個網頁不是同源的,該屬性回傳null

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

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

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

55.2.6 window.top,window.parent

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

window.parent屬性指向父視窗,如果當前視窗沒有父視窗,window.parent指向自身,

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

對于不包含框架的網頁,這兩個屬性等同于window物件,

55.2.7 window.status

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

55.2.8 window.devicePixelRatio

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

55.2.9 位置大小屬性

以下屬性回傳window物件的位置資訊和大小資訊,

(1)window.screenX,window.screenY

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

(2) window.innerHeight,window.innerWidth

window.innerHeightwindow.innerWidth屬性,回傳網頁在當前視窗中可見部分的高度和寬度,即“視口”(viewport)的大小(單位像素),這兩個屬性只讀,

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

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

(3)window.outerHeight,window.outerWidth

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

(4)window.scrollX,window.scrollY

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

注意,這兩個屬性的回傳值不是整數,而是雙精度浮點數,如果頁面沒有滾動,它們的值就是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別名,

55.2.10 組件屬性

組件屬性回傳瀏覽器的組件物件,這樣的屬性有下面幾個,

  • window.locationbar:地址欄物件
  • window.menubar:選單欄物件
  • window.scrollbars:視窗的滾動條物件
  • window.toolbar:工具列物件
  • window.statusbar:狀態欄物件
  • window.personalbar:用戶安裝的個人工具列物件

這些物件的visible屬性是一個布林值,表示這些組件是否可見,這些屬性只讀,

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

55.2.11 全域物件屬性

全域物件屬性指向一些瀏覽器原生的全域物件,

  • window.document:指向document物件,詳見《document 物件》一章,注意,這個屬性有同源限制,只有來自同源的腳本才能讀取這個屬性,
  • window.location:指向Location物件,用于獲取當前視窗的 URL 資訊,它等同于document.location屬性,詳見《Location 物件》一章,
  • window.navigator:指向Navigator物件,用于獲取環境資訊,詳見《Navigator 物件》一章,
  • window.history:指向History物件,表示瀏覽器的瀏覽歷史,詳見《History 物件》一章,
  • window.localStorage:指向本地儲存的 localStorage 資料,詳見《Storage 介面》一章,
  • window.sessionStorage:指向本地儲存的 sessionStorage 資料,詳見《Storage 介面》一章,
  • window.console:指向console物件,用于操作控制臺,詳見《console 物件》一章,
  • window.screen:指向Screen物件,表示螢屏資訊,詳見《Screen 物件》一章,

55.2.12 window.isSecureContext

window.isSecureContext屬性回傳一個布林值,表示當前視窗是否處在加密環境,如果是 HTTPS 協議,就是true,否則就是false

55.3 window 物件的方法

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

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

(1)window.alert()

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

window.alert('Hello World');

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

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

alert('本條提示\n分成兩行');
(2)window.prompt()

window.prompt()方法彈出的對話框,提示文字的下方,**還有一個輸入框,要求用戶輸入資訊,**并有“確定”和“取消”兩個按鈕,它往往用來獲取用戶輸入的資料,

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

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

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

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

window.prompt()方法的第二個引數是可選的,但是最好總是提供第二個引數,作為輸入框的默認值,

(3)window.confirm()

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

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

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

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

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

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

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

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

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

(1)window.open()

window.open方法用于新建另一個瀏覽器視窗,類似于瀏覽器選單的新建視窗選項,它會回傳新視窗的參考,如果無法新建視窗,則回傳null

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

上面代碼會讓瀏覽器彈出一個新建視窗,網址是當前域名下的somefile.html

open方法一共可以接受三個引數,

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

下面是一個例子,

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

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

第三個引數可以設定如下屬性,

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

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

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

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

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

window.open方法回傳新視窗的參考,

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

注意,如果新視窗和父視窗不是同源的(即不在同一個域),它們彼此不能獲取對方視窗物件的內部屬性,

下面是另一個例子,

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

上面代碼先打開一個新視窗,然后在該視窗彈出一個對話框,再將網址導向example.com

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

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

window.close方法用于關閉當前視窗,一般只用來關閉window.open方法新建的視窗,

popup.close()

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

(3)window.stop()

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

window.stop()

55.3.3 window.moveTo(),window.moveBy()

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

window.moveTo(100, 200)

上面代碼將視窗移動到螢屏(100, 200)的位置,

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

window.moveBy(25, 50)

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

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

55.3.4 window.resizeTo(),window.resizeBy()

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

它接受兩個引數,第一個是縮放后的視窗寬度(outerWidth屬性,包含滾動條、標題欄等等),第二個是縮放后的視窗高度(outerHeight屬性),

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

上面代碼將當前視窗縮放到,螢屏可用區域的一半寬度和高度,

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

它接受兩個引數,第一個是水平縮放的量,第二個是垂直縮放的量,單位都是像素,

window.resizeBy(-200, -200)

上面的代碼將當前視窗的寬度和高度,都縮小200像素,

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

window.scrollTo方法用于將檔案滾動到指定位置,它接受兩個引數,表示滾動后位于視窗左上角的頁面坐標,

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

它也可以接受一個配置物件作為引數,

window.scrollTo(options)

配置物件options有三個屬性,

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

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

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

window.scrollBy(0, window.innerHeight)

上面代碼用于將網頁向下滾動一屏,

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

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

55.3.6 window.print()

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

常見的列印按鈕代碼如下,

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

非桌面設備(比如手機)可能沒有列印功能,這時可以這樣判斷,

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

55.3.7 window.focus(),window.blur()

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

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

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

上面代碼先檢查popup視窗是否依然存在,確認后激活該視窗,

window.blur()方法將焦點從視窗移除,

當前視窗獲得焦點時,會觸發focus事件;當前視窗失去焦點時,會觸發blur事件,

55.3.8 window.getSelection()

window.getSelection方法回傳一個Selection物件,表示用戶現在選中的文本,

var selObj = window.getSelection();

使用Selection物件的toString方法可以得到選中的文本,

var selectedText = selObj.toString();

55.3.9 window.getComputedStyle(),window.matchMedia()

window.getComputedStyle()方法接受一個元素節點作為引數,回傳一個包含該元素的最終樣式資訊的物件,詳見《CSS 操作》一章,

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

55.3.10 window.requestAnimationFrame()(54.3.3)

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

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

該方法接受一個回呼函式作為引數,

window.requestAnimationFrame(callback)

上面代碼中,callback是一個回呼函式,callback執行時,它的引數就是系統傳入的一個高精度時間戳(performance.now()的回傳值),單位是毫秒,表示距離網頁加載的時間,

window.requestAnimationFrame()的回傳值是一個整數,這個整數可以傳入window.cancelAnimationFrame(),用來取消回呼函式的執行,

下面是一個window.requestAnimationFrame()執行網頁影片的例子,

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';
  // 如果距離第一次執行不超過 2000 毫秒,
  // 就繼續執行影片
  if (progress < 2000) {
    window.requestAnimationFrame(step);
  }
}

window.requestAnimationFrame(step);

上面代碼定義了一個網頁影片,持續時間是2秒,會讓元素向右移動,

55.3.11 window.requestIdleCallback()

window.requestIdleCallback()setTimeout類似,也是將某個函式推遲執行,但是它保證將回呼函式推遲到系統資源空閑時執行,也就是說,如果某個任務不是很關鍵,就可以使用window.requestIdleCallback()將其推遲執行,以保證網頁性能,

它跟window.requestAnimationFrame()的區別在于,后者指定回呼函式在下一次瀏覽器重排時執行,問題在于下一次重排時,系統資源未必空閑,不一定能保證在16毫秒之內完成;window.requestIdleCallback()可以保證回呼函式在系統資源空閑時執行,

該方法接受一個回呼函式和一個配置物件作為引數,配置物件可以指定一個推遲執行的最長時間,如果過了這個時間,回呼函式不管系統資源有無空閑,都會執行,

window.requestIdleCallback(callback[, options])

callback引數是一個回呼函式,該回呼函式執行時,系統會傳入一個IdleDeadline物件作為引數,IdleDeadline物件有一個didTimeout屬性(布林值,表示是否為超時呼叫)和一個timeRemaining()方法(回傳該空閑時段剩余的毫秒數),

options引數是一個配置物件,目前只有timeout一個屬性,用來指定回呼函式推遲執行的最大毫秒數,該引數可選,

window.requestIdleCallback()方法回傳一個整數,該整數可以傳入window.cancelIdleCallback()取消回呼函式,

下面是一個例子,

requestIdleCallback(myNonEssentialWork);

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

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

下面是指定timeout的例子,

requestIdleCallback(processPendingAnalyticsEvents, { timeout: 2000 });

上面代碼指定,processPendingAnalyticsEvents必須在未來2秒之內執行,

如果由于超時導致回呼函式執行,則deadline.timeRemaining()回傳0deadline.didTimeout回傳true

如果多次執行window.requestIdleCallback(),指定多個回呼函式,那么這些回呼函式將排成一個佇列,按照先進先出的順序執行,

55.4 事件

window物件可以接收以下事件,

55.4.1 load 事件和 onl oad 屬性

load事件發生在檔案在瀏覽器視窗加載完畢時,window.onload屬性可以指定這個事件的回呼函式,

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

上面代碼在網頁加載完畢后,獲取指定元素并進行處理,

55.4.2 error 事件和 one rror 屬性

瀏覽器腳本發生錯誤時,會觸發window物件的error事件,我們可以通過window.onerror屬性對該事件指定回呼函式,

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

由于歷史原因,windowerror事件的回呼函式不接受錯誤物件作為引數,而是一共可以接受五個引數,它們的含義依次如下,

  • 出錯資訊
  • 出錯腳本的網址
  • 行號
  • 列號
  • 錯誤物件

老式瀏覽器只支持前三個引數,

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

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

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

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

Access-Control-Allow-Origin: *

然后,在網頁的<script>標簽中設定crossorigin屬性,

<script crossorigin="anonymous" src="//example.com/file.js"></script>

上面代碼的crossorigin="anonymous"表示,讀取檔案不需要身份資訊,即不需要 cookie 和 HTTP 認證資訊,如果設為crossorigin="use-credentials",就表示瀏覽器會上傳 cookie 和 HTTP 認證資訊,同時還需要服務器端打開 HTTP 頭資訊Access-Control-Allow-Credentials

55.4.3 window 物件的事件監聽屬性

除了具備元素節點都有的 GlobalEventHandlers 介面,window物件還具有以下的事件監聽函式屬性,

  • window.onafterprintafterprint事件的監聽函式,
  • window.onbeforeprintbeforeprint事件的監聽函式,
  • window.onbeforeunloadbeforeunload事件的監聽函式,
  • window.onhashchangehashchange事件的監聽函式,
  • window.onlanguagechange: languagechange的監聽函式,
  • window.onmessagemessage事件的監聽函式,
  • window.onmessageerrorMessageError事件的監聽函式,
  • window.onofflineoffline事件的監聽函式,
  • window.ononlineonline事件的監聽函式,
  • window.onpagehidepagehide事件的監聽函式,
  • window.onpageshowpageshow事件的監聽函式,
  • window.onpopstatepopstate事件的監聽函式,
  • window.onstoragestorage事件的監聽函式,
  • window.onunhandledrejection:未處理的 Promise 物件的reject事件的監聽函式,
  • window.onunloadunload事件的監聽函式,

55.5 多視窗操作

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

55.5.1 視窗的參考

各個視窗之中的腳本,可以參考其他視窗,瀏覽器提供了一些特殊變數,用來回傳其他視窗,

  • top:頂層視窗,即最上層的那個視窗
  • parent:父視窗
  • self:當前視窗,即自身

下面代碼可以判斷,當前視窗是否為頂層視窗,

if (window.top === window.self) {
  // 當前視窗是頂層視窗
} else {
  // 當前視窗是子視窗
}

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

window.parent.history.back();

與這些變數對應,瀏覽器還提供一些特殊的視窗名,供window.open()方法、<a>標簽、<form>標簽等參考,

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

下面代碼就表示在頂層視窗打開鏈接,

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

55.5.2 iframe 元素

對于iframe嵌入的視窗,document.getElementById方法可以拿到該視窗的 DOM 節點,然后使用contentWindow屬性獲得iframe節點包含的window物件,

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

上面代碼中,frame.contentWindow可以拿到子視窗的window物件,然后,在滿足同源限制的情況下,可以讀取子視窗內部的屬性,

// 獲取子視窗的標題
frameWindow.title

/ 元素的contentDocument屬性,可以拿到子視窗的document物件,

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

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

/ 元素遵守同源政策,只有當父視窗與子視窗在同一個域時,兩者之間才可以用腳本通信,否則只有使用window.postMessage方法,

/ 視窗內部,使用window.parent參考父視窗,如果當前頁面沒有父視窗,則window.parent屬性回傳自身,因此,可以通過window.parent是否等于window.self,判斷當前視窗是否為iframe視窗,

if (window.parent !== window.self) {
  // 當前視窗是子視窗
}

/ 視窗的window物件,有一個frameElement屬性,回傳在父視窗中的 DOM 節點,對于非嵌入的視窗,該屬性等于null,

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

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

55.5.3 window.frames 屬性

window.frames屬性回傳一個類似陣列的物件,成員是所有子視窗的window物件,可以使用這個屬性,實作視窗之間的互相參考,比如,frames[0]回傳第一個子視窗,frames[1].frames[2]回傳第二個子視窗內部的第三個子視窗,parent.frames[1]回傳父視窗的第二個子視窗,

注意,window.frames每個成員的值,是框架內的視窗(即框架的window物件),而不是iframe標簽在父視窗的 DOM 節點,如果要獲取每個框架內部的 DOM 樹,需要使用window.frames[0].document的寫法,

另外,如果<iframe>元素設定了nameid屬性,那么屬性值會自動成為全域變數,并且可以通過window.frames屬性參考,回傳子視窗的window物件,

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

另外,name屬性的值會自動成為子視窗的名稱,可以用在window.open方法的第二個引數,或者<a><frame>標簽的target屬性,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/290902.html

標籤:其他

上一篇:JavaScript入門第四章(運算子與運算式上 )

下一篇:JavaScript(七)(Navigator/Screen/Cookie/XMLHttpRequest/CORS)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • vue移動端上拉加載

    可能做得過于簡單或者比較low,請各位大佬留情,一起探討技術 ......

    uj5u.com 2020-09-10 04:38:07 more
  • 優美網站首頁,頂部多層導航

    一個個人用的瀏覽器首頁,可以把一下常用的網站放在這里,平常打開會比較方便。 第一步,HTML代碼 <script src=https://www.cnblogs.com/szharf/p/"js/jquery-3.4.1.min.js"></script> <div id="navigate"> <ul> <li class="labels labels_1"> ......

    uj5u.com 2020-09-10 04:38:47 more
  • 頁面為要加<!DOCTYPE html>

    最近因為寫一個js函式,需要用到$(window).height(); 由于手寫demo的時候,過于自信,其實對前端方面的認識也不夠體系,用文本檔案直接敲出來的html代碼,第一行沒有加上<!DOCTYPE html> 導致了$(window).height();的結果直接是整個document的高 ......

    uj5u.com 2020-09-10 04:38:52 more
  • WordPress網站程式手動升級要做好資料備份

    WordPress博客網站程式在進行升級前,必須要做好網站資料的備份,這個問題良家佐言是遇見過的;在剛開始接觸WordPress博客程式的時候,因為升級問題和博客網站的修改的一些嘗試,良家佐言是吃盡了苦頭。因為購買的是西部數碼的空間和域名,每當佐言把自己的WordPress博客網站搞到一塌糊涂的時候 ......

    uj5u.com 2020-09-10 04:39:30 more
  • WordPress程式不能升級為5.4.2版本的原因

    WordPress是一款個人博客系統,受到英文博客愛好者和中文博客愛好者的追捧,并逐步演化成一款內容管理系統軟體;它是使用PHP語言和MySQL資料庫開發的,用戶可以在支持PHP和MySQL資料庫的服務器上使用自己的博客。每一次WordPress程式的更新,就會牽動無數WordPress愛好者的心, ......

    uj5u.com 2020-09-10 04:39:49 more
  • 使用CSS3的偽元素進行首字母下沉和首行改變樣式

    網頁中常見的一種效果,首字改變樣式或者首行改變樣式,效果如下圖。 代碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, ......

    uj5u.com 2020-09-10 04:40:09 more
  • 關于a標簽的講解

    什么是a標簽? <a> 標簽定義超鏈接,用于從一個頁面鏈接到另一個頁面。 <a> 元素最重要的屬性是 href 屬性,它指定鏈接的目標。 a標簽的語法格式:<a href=https://www.cnblogs.com/summerxbc/p/"指定要跳轉的目標界面的鏈接">需要展示給用戶看見的內容</a> a標簽 在所有瀏覽器中,鏈接的默認外觀如下: 未被訪問的鏈接帶 ......

    uj5u.com 2020-09-10 04:40:11 more
  • 前端輪播圖

    在需要輪播的頁面是引入swiper.min.js和swiper.min.css swiper.min.js地址: 鏈接:https://pan.baidu.com/s/15Uh516YHa4CV3X-RyjEIWw 提取碼:4aks swiper.min.css地址 鏈接:https://pan.b ......

    uj5u.com 2020-09-10 04:40:13 more
  • 如何設定html中的背景圖片(全屏顯示,且不拉伸)

    1 <style>2 body{background-image:url(https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture); 3 background-size:cover;background ......

    uj5u.com 2020-09-10 04:40:16 more
  • Java學習——HTML詳解(上)

    HTML詳解 初識HTML Hyper Text Markup Language(超文本標記語言) 1 <!--DOCTYPE:告訴瀏覽器我們要使用什么規范--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <!--meta 描述性的標簽,描述一些 ......

    uj5u.com 2020-09-10 04:40:33 more
最新发布
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 07:59:23 more
  • 生產事故-走近科學之消失的JWT

    入職多年,面對生產環境,盡管都是小心翼翼,慎之又慎,還是難免捅出簍子。輕則滿頭大汗,面紅耳赤。重則系統停擺,損失資金。每一個生產事故的背后,都是寶貴的經驗和教訓,都是專案成員的血淚史。為了更好地防范和遏制今后的各類事故,特開此專題,長期更新和記錄大大小小的各類事故。有些是親身經歷,有些是經人耳傳口授 ......

    uj5u.com 2023-04-18 07:55:04 more
  • 記錄--Canvas實作打飛字游戲

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 打開游戲界面,看到一個畫面簡潔、卻又富有挑戰性的游戲。螢屏上,有一個白色的矩形框,里面不斷下落著各種單詞,而我需要迅速地輸入這些單詞。如果我輸入的單詞與螢屏上的單詞匹配,那么我就可以獲得得分;如果我輸入的單詞錯誤或者時間過長,那么我就會輸 ......

    uj5u.com 2023-04-04 08:35:30 more
  • 了解 HTTP 看這一篇就夠

    在學習網路之前,了解它的歷史能夠幫助我們明白為何它會發展為如今這個樣子,引發探究網路的興趣。下面的這張圖片就展示了“互聯網”誕生至今的發展歷程。 ......

    uj5u.com 2023-03-16 11:00:15 more
  • 藍牙-低功耗中心設備

    //11.開啟藍牙配接器 openBluetoothAdapter //21.開始搜索藍牙設備 startBluetoothDevicesDiscovery //31.開啟監聽搜索藍牙設備 onBluetoothDeviceFound //30.停止監聽搜索藍牙設備 offBluetoothDevi ......

    uj5u.com 2023-03-15 09:06:45 more
  • canvas畫板(滑鼠和觸摸)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>canves</title> <style> #canvas { cursor:url(../images/pen.png),crosshair; } #canvasdiv{ bo ......

    uj5u.com 2023-02-15 08:56:31 more
  • 手機端H5 實作自定義拍照界面

    手機端 H5 實作自定義拍照界面也可以使用 MediaDevices API 和 <video> 標簽來實作,和在桌面端做法基本一致。 首先,使用 MediaDevices.getUserMedia() 方法獲取攝像頭媒體流,并將其傳遞給 <video> 標簽進行渲染。 接著,使用 HTML 的 < ......

    uj5u.com 2023-01-12 07:58:22 more
  • 記錄--短視頻滑動播放在 H5 下的實作

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 短視頻已經無數不在了,但是主體還是使用 app 來承載的。本文講述 H5 如何實作 app 的視頻滑動體驗。 無聲勝有聲,一圖頂百辯,且看下圖: 網址鏈接(需在微信或者手Q中瀏覽) 從上圖可以看到,我們主要實作的功能也是本文要講解的有: ......

    uj5u.com 2023-01-04 07:29:05 more
  • 一文讀懂 HTTP/1 HTTP/2 HTTP/3

    從 1989 年萬維網(www)誕生,HTTP(HyperText Transfer Protocol)經歷了眾多版本迭代,WebSocket 也在期間萌芽。1991 年 HTTP0.9 被發明。1996 年出現了 HTTP1.0。2015 年 HTTP2 正式發布。2020 年 HTTP3 或能正... ......

    uj5u.com 2022-12-24 06:56:02 more
  • 【HTML基礎篇002】HTML之form表單超詳解

    ??一、form表單是什么

    ??二、form表單的屬性

    ??三、input中的各種Type屬性值

    ??四、標簽 ......

    uj5u.com 2022-12-18 07:17:06 more