用框架的你,可能早已忽略了這些事件API

DOMContentLoaded,load,beforeunload,unload

HTML 頁面的生命周期包含三個重要事件:

  • DOMContentLoaded —— 瀏覽器已完全加載 HTML,并構建了 DOM 樹,但像 <img> 和樣式表之類的外部資源可能尚未加載完成。

  • load —— 瀏覽器不僅加載完成了 HTML,還加載完成了所有外部資源:圖片,樣式等。

  • beforeunload/unload —— 當用戶正在離開頁面時。

每個事件都是有用的:

  • DOMContentLoaded 事件 —— DOM 已經就緒,因此處理程序可以查找 DOM 節點,并初始化接口。

  • load 事件 —— 外部資源已加載完成,樣式已被應用,圖片大小也已知了。

  • beforeunload 事件 —— 用戶正在離開:我們可以檢查用戶是否保存了更改,并詢問他是否真的要離開。

  • unload 事件 —— 用戶幾乎已經離開了,但是我們仍然可以啟動一些操作,例如發送統計數據。

我們探索一下這些事件的細節。

DOMContentLoaded

DOMContentLoaded 事件發生在 document 對象上。

我們必須使用 addEventListener 來捕獲它:

document.addEventListener("DOMContentLoaded",?ready);
//?不是?"document.onDOMContentLoaded?=?..."

例如:

<script>function?ready()?{alert('DOM?is?ready');//?圖片目前尚未加載完成(除非已經被緩存),所以圖片的大小為?0x0alert(`Image?size:?${img.offsetWidth}x${img.offsetHeight}`);}document.addEventListener("DOMContentLoaded",?ready);
</script><img?id="img"?src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">

在示例中,DOMContentLoaded 處理程序在文檔加載完成后觸發,所以它可以查看所有元素,包括它下面的 <img> 元素。

但是,它不會等待圖片加載。因此,alert 顯示其大小為零。

乍一看,DOMContentLoaded 事件非常簡單。DOM 樹準備就緒 —— 這是它的觸發條件。它并沒有什么特別之處。

DOMContentLoaded 和腳本

當瀏覽器處理一個 HTML 文檔,并在文檔中遇到 <script> 標簽時,就會在繼續構建 DOM 之前運行它。這是一種防范措施,因為腳本可能想要修改 DOM,甚至對其執行 document.write 操作,所以 DOMContentLoaded 必須等待腳本執行結束。

因此,DOMContentLoaded 肯定在下面的這些腳本執行結束之后發生:

<script>document.addEventListener("DOMContentLoaded",?()?=>?{alert("DOM?ready!");});
</script><script?src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"></script><script>alert("Library?loaded,?inline?script?executed");
</script>

在上面這個例子中,我們首先會看到 "Library loaded...",然后才會看到 "DOM ready!"(所有腳本都已經執行結束)。

不會阻塞 DOMContentLoaded 的腳本:

此規則有兩個例外:

  1. 具有 async 特性(attribute)的腳本不會阻塞 DOMContentLoaded,稍后[1] 我們會講到。

  2. 使用 document.createElement('script') 動態生成并添加到網頁的腳本也不會阻塞 DOMContentLoaded

DOMContentLoaded 和樣式

外部樣式表不會影響 DOM,因此 DOMContentLoaded 不會等待它們。

但這里有一個陷阱。如果在樣式后面有一個腳本,那么該腳本必須等待樣式表加載完成:

<link?type="text/css"?rel="stylesheet"?href="style.css">
<script>//?在樣式表加載完成之前,腳本都不會執行alert(getComputedStyle(document.body).marginTop);
</script>

原因是,腳本可能想要獲取元素的坐標和其他與樣式相關的屬性,如上例所示。因此,它必須等待樣式加載完成。

DOMContentLoaded 等待腳本時,它現在也在等待腳本前面的樣式。

瀏覽器內建的自動填充

Firefox,Chrome 和 Opera 都會在 DOMContentLoaded 中自動填充表單。

例如,如果頁面有一個帶有登錄名和密碼的表單,并且瀏覽器記住了這些值,那么在 DOMContentLoaded 上,瀏覽器會嘗試自動填充它們(如果得到了用戶允許)。

因此,如果 DOMContentLoaded 被需要加載很長時間的腳本延遲觸發,那么自動填充也會等待。你可能在某些網站上看到過(如果你使用瀏覽器自動填充)—— 登錄名/密碼字段不會立即自動填充,而是在頁面被完全加載前會延遲填充。這實際上是 DOMContentLoaded 事件之前的延遲。

window.onload

當整個頁面,包括樣式、圖片和其他資源被加載完成時,會觸發 window 對象上的 load 事件。可以通過 onload 屬性獲取此事件。

下面的這個示例正確顯示了圖片大小,因為 window.onload 會等待所有圖片加載完畢:

<script>window.onload?=?function()?{?//?與此相同?window.addEventListener('load',?(event)?=>?{alert('Page?loaded');//?此時圖片已經加載完成alert(`Image?size:?${img.offsetWidth}x${img.offsetHeight}`);};
</script><img?id="img"?src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">

window.onunload

當訪問者離開頁面時,window 對象上的 unload 事件就會被觸發。我們可以在那里做一些不涉及延遲的操作,例如關閉相關的彈出窗口。

有一個值得注意的特殊情況是發送分析數據。

假設我們收集有關頁面使用情況的數據:鼠標點擊,滾動,被查看的頁面區域等。

自然地,當用戶要離開的時候,我們希望通過 unload 事件將數據保存到我們的服務器上。

有一個特殊的 navigator.sendBeacon(url, data) 方法可以滿足這種需求,詳見規范 https://w3c.github.io/beacon/。

它在后臺發送數據,轉換到另外一個頁面不會有延遲:瀏覽器離開頁面,但仍然在執行 sendBeacon

使用方式如下:

let?analyticsData?=?{?/*?帶有收集的數據的對象?*/?};window.addEventListener("unload",?function()?{navigator.sendBeacon("/analytics",?JSON.stringify(analyticsData));
});
  • 請求以 POST 方式發送。

  • 我們不僅能發送字符串,還能發送表單以及其他格式的數據,在 Fetch 一章有詳細講解,但通常它是一個字符串化的對象。

  • 數據大小限制在 64kb。

sendBeacon 請求完成時,瀏覽器可能已經離開了文檔,所以就無法獲取服務器響應(對于分析數據來說通常為空)。

還有一個 keep-alive 標志,該標志用于在 fetch[2] 方法中為通用的網絡請求執行此類“離開頁面后”的請求。你可以在 Fetch API[3] 一章中找到更多相關信息。

如果我們要取消跳轉到另一頁面的操作,在這里做不到。但是我們可以使用另一個事件 —— onbeforeunload

window.onbeforeunload

如果訪問者觸發了離開頁面的導航(navigation)或試圖關閉窗口,beforeunload 處理程序將要求進行更多確認。

如果我們要取消事件,瀏覽器會詢問用戶是否確定。

你可以通過運行下面這段代碼,然后重新加載頁面來進行嘗試:

window.onbeforeunload?=?function()?{return?false;
};

由于歷史原因,返回非空字符串也被視為取消事件。在以前,瀏覽器曾經將其顯示為消息,但是根據 現代規范[4] 所述,它們不應該這樣。

這里有個例子:

window.onbeforeunload?=?function()?{return?"There?are?unsaved?changes.?Leave?now?";
};

它的行為已經改變了,因為有些站長通過顯示誤導性和惡意信息濫用了此事件處理程序。所以,目前一些舊的瀏覽器可能仍將其顯示為消息,但除此之外 —— 無法自定義顯示給用戶的消息。

readyState

如果我們將 DOMContentLoaded 事件處理程序設置在文檔加載完成之后,會發生什么?

很自然地,它永遠不會運行。

在某些情況下,我們不確定文檔是否已經準備就緒。我們希望我們的函數在 DOM 加載完成時執行,無論現在還是以后。

document.readyState 屬性可以為我們提供當前加載狀態的信息。

它有 3 個可能值:

  • loading —— 文檔正在被加載。

  • interactive —— 文檔被全部讀取。

  • complete —— 文檔被全部讀取,并且所有資源(例如圖片等)都已加載完成。

所以,我們可以檢查 document.readyState 并設置一個處理程序,或在代碼準備就緒時立即執行它。

像這樣:

function?work()?{?/*...*/?}if?(document.readyState?==?'loading')?{//?仍在加載,等待事件document.addEventListener('DOMContentLoaded',?work);
}?else?{// DOM 已就緒!work();
}

還有一個 readystatechange 事件,會在狀態發生改變時觸發,因此我們可以打印所有這些狀態,就像這樣:

//?當前狀態
console.log(document.readyState);//?狀態改變時打印它
document.addEventListener('readystatechange',?()?=>?console.log(document.readyState));

readystatechange 事件是跟蹤文檔加載狀態的另一種機制,它很早就存在了。現在則很少被使用。

但是為了完整起見,讓我們看看完整的事件流。

這是一個帶有 <iframe><img> 和記錄事件的處理程序的文檔:

<script>log('initial?readyState:'?+?document.readyState);document.addEventListener('readystatechange',?()?=>?log('readyState:'?+?document.readyState));document.addEventListener('DOMContentLoaded',?()?=>?log('DOMContentLoaded'));window.onload?=?()?=>?log('window?onload');
</script><iframe?src="iframe.html"?onload="log('iframe?onload')"></iframe><img?src="http://en.js.cx/clipart/train.gif"?id="img">
<script>img.onload?=?()?=>?log('img?onload');
</script>

此示例運行 在 sandbox 中[5]

典型輸出:

  1. [1] initial readyState:loading

  2. [2] readyState:interactive

  3. [2] DOMContentLoaded

  4. [3] iframe onload

  5. [4] img onload

  6. [4] readyState:complete

  7. [4] window onload

方括號中的數字表示發生這種情況的大致時間。標有相同數字的事件幾乎是同時發生的(+- 幾毫秒)。

  • DOMContentLoaded 之前,document.readyState 會立即變成 interactive。它們倆的意義實際上是相同的。

  • 當所有資源(iframeimg)都加載完成后,document.readyState 變成 complete。這里我們可以發現,它與 img.onloadimg 是最后一個資源)和 window.onload 幾乎同時發生。轉換到 complete 狀態的意義與 window.onload 相同。區別在于 window.onload 始終在所有其他 load 處理程序之后運行。

總結

頁面生命周期事件:

  • 當 DOM 準備就緒時,document 上的 DOMContentLoaded 事件就會被觸發。在這個階段,我們可以將 JavaScript 應用于元素。

    • 諸如 <script>...</script><script src="..."></script> 之類的腳本會阻塞 ?DOMContentLoaded,瀏覽器將等待它們執行結束。

    • 圖片和其他資源仍然可以繼續被加載。

  • 當頁面和所有資源都加載完成時,window 上的 load 事件就會被觸發。我們很少使用它,因為通常無需等待那么長時間。

  • 當用戶想要離開頁面時,window 上的 beforeunload 事件就會被觸發。如果我們取消這個事件,瀏覽器就會詢問我們是否真的要離開(例如,我們有未保存的更改)。

  • 當用戶最終離開時,window 上的 unload 事件就會被觸發。在處理程序中,我們只能執行不涉及延遲或詢問用戶的簡單操作。正是由于這個限制,它很少被使用。我們可以使用 navigator.sendBeacon 來發送網絡請求。

  • document.readyState 是文檔的當前狀態,可以在 readystatechange 事件中跟蹤狀態更改:

    • loading —— 文檔正在被加載。

    • interactive —— 文檔已被解析完成,與 DOMContentLoaded 幾乎同時發生,但是在 DOMContentLoaded 之前發生。

    • complete —— 文檔和資源均已加載完成,與 window.onload 幾乎同時發生,但是在 window.onload 之前發生。


現代 JavaScript 教程:開源的現代 JavaScript 從入門到進階的優質教程。React 官方文檔推薦,與 MDN 并列的 JavaScript 學習教程[6]

在線免費閱讀:https://zh.javascript.info


參考資料

[1]

稍后: https://zh.javascript.info/script-async-defer

[2]

fetch: https://zh.javascript.info/fetch

[3]

Fetch API: https://zh.javascript.info/fetch-api

[4]

現代規范: https://html.spec.whatwg.org/#unloading-documents

[5]

在 sandbox 中: https://plnkr.co/edit/ct5SNvrHCA75b2KZ?p=preview

[6]

React 官方文檔推薦,與 MDN 并列的 JavaScript 學習教程: https://zh-hans.reactjs.org/docs/getting-started.html#javascript-resources

推薦閱讀

我在阿里招前端,我該怎么幫你?(現在還可以加模擬面試群)
如何拿下阿里巴巴 P6 的前端 Offer
如何準備阿里P6/P7前端面試--項目經歷準備篇
大廠面試官常問的亮點,該如何做出?
如何從初級到專家(P4-P7)打破成長瓶頸和有效突破
若川知乎問答:2年前端經驗,做的項目沒什么技術含量,怎么辦?
若川知乎高贊:有哪些必看的 JS庫?

末尾

你好,我是若川,江湖人稱菜如若川,歷時一年只寫了一個學習源碼整體架構系列~(點擊藍字了解我)

  1. 關注若川視野,回復"pdf" 領取優質前端書籍pdf,回復"1",可加群長期交流學習

  2. 我的博客地址:https://lxchuan12.gitee.io?歡迎收藏

  3. 覺得文章不錯,可以點個在看呀^_^另外歡迎留言交流~

精選前端好文,伴你不斷成長

若川原創文章精選!可點擊

小提醒:若川視野公眾號面試、源碼等文章合集在菜單欄中間【源碼精選】按鈕,歡迎點擊閱讀,也可以星標我的公眾號,便于查找

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/276244.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/276244.shtml
英文地址,請注明出處:http://en.pswp.cn/news/276244.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

調用接口登錄禪道_有java調用api登錄并驗證禪道的實例嗎

展開全部本文實例為大家分享了32313133353236313431303231363533e78988e69d8331333363396466JAVA的短信驗證碼api調用代碼&#xff0c;供大家參考&#xff0c;具體內容如下import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.IOException;import j…

[Docker]Docker快速上手學習筆記

0. 學習的一些疑問 如何熱更新鏡像(images)&#xff1f;&#xff08;你可以快速啟動或者銷毀容器。這種時間幾乎是實時的&#xff09;如何熱更新游戲服&#xff1f;好處在于各個應用之間環境相互獨立&#xff0c;即使某一個容器崩潰也不會影響到其它容器&#xff1b;每個容器使…

原來 Clipboard 還能復制圖像?原理是什么

在寫了 這個 29.7 K 的剪貼板 JS 庫有點東西&#xff01; 這篇文章之后&#xff0c;收到了小伙伴提的兩個問題&#xff1a;1.clipboard.js 這個庫除了復制文字之外&#xff0c;能復制圖像么&#xff1f;2.clipboard.js 這個庫依賴的 document.execCommand API 已被廢棄了&…

計算機大數據的前景方向_計算機方向,網絡與信息安全和大數據哪個前景好一點?...

大數據是我目前的研究方向之一&#xff0c;我也曾經做過網絡安全相關的項目&#xff0c;主要涉及的是各種網絡環境下數據傳輸的安全處理方案。另外&#xff0c;我曾經給高校的學生做過網絡安全的系列講座&#xff0c;系統地整理過網絡安全的相關內容&#xff0c;所以我來談一談…

Smarty 顯示大括號 | 在Smarty中計算數組元素的長度 | Smarty字符串拼接

參考鏈接&#xff1a;http://hi.baidu.com/bdusnb/item/289d160e6a9c92cd9157183d 參考鏈接&#xff1a;http://hi.baidu.com/mayimu789/item/b565088d047da0d05f0ec16f 參考鏈接&#xff1a;http://blog.sina.com.cn/s/blog_8155e74d0101el2k.html Smarty 3 &#xff1a;大…

ftp協議分析(一)

作者: 肖建彬 | 可以轉載, 轉載時務必以超鏈接形式標明文章原始出處和作者信息及版權聲明網址&#xff1a;http://www.xiaojb.com/archives/it/ftp.shtml根據是使用port模式還是passive模式&#xff0c;ftp使用不同的tcp端口號&#xff0c;在詳細描述ftp前&#xff0c;我們來簡…

JavaScript 元編程

大家好&#xff0c;我是若川。今天給分享一篇來自freecodecamp的好文。我是freecodecamp杭州社區組織者之一&#xff0c;有一群小伙伴一起組織線下分享活動&#xff0c;不過2020年我們杭州社區幾乎沒有活躍&#xff0c;我也沒有什么貢獻。另外&#xff0c;我的公眾號「若川視野…

python 異常處理模塊_擴展Python模塊系列(五)----異常和錯誤處理

在上一節中&#xff0c;討論了在用C語言擴展Python模塊時&#xff0c;應該如何處理無處不在的引用計數問題。重點關注的是在實現一個C Python的函數時&#xff0c;對于一個PyObject對象&#xff0c;何時調用Py_INCREF和Py_DECREF。在編寫C語言代碼時&#xff0c;需要了解Python…

常見的php筆試題(附答案)搜集整理

轉載鏈接&#xff1a;http://www.yaojinbu.com/p/139.html 常見的php筆試題&#xff08;附答案&#xff09;搜集整理 1.在PHP中&#xff0c;當前腳本的名稱&#xff08;不包括路徑和查詢字符串&#xff09;記錄在哪個預定義變量中&#xff1f;而鏈接到當前頁面的URL又記錄在哪個…

Js整理備忘(02)——運算符

1、運算符的表示以及優先級 Javascript&#xff08;以下簡寫為Js&#xff09;的大部分運算符與C或Java是類似的。 記得剛學C語言時老師講的優先級口訣&#xff0c;非常好記&#xff1a;“括、單、算、移、關”“位、邏、條、賦、逗”&#xff0c;此處也可以套用一下&#xff0c…

手寫一個合格的前端腳手架

為什么我們需要一套腳手架為什么我們需要一套腳手架&#xff0c;它能幫助我們解決哪些痛點問題。?前端項目配置越來越繁瑣、耗時&#xff0c;重復無意義的工作?項目結構不統一、不規范?前端項目類型繁多&#xff0c;不同項目不同配置&#xff0c;管理成本高?腳手架也可以是…

第一篇cnblog!

本人才疏學淺&#xff0c;終于通過了cnblog的審核&#xff0c;興奮之余&#xff0c;發表感言——不容易啊&#xff01;在我的博聞里面&#xff0c;隨筆類當然就是技術類的比較多的&#xff0c;特別是實例類的。理論類的大部分放在文章板塊&#xff0c;本人e文特別好(哈哈&#…

解決error 1045: Access denied for user: 'root@localhost' (Using password: YES)

轉載連接&#xff1a;http://jianfw2009.blog.163.com/blog/static/13431366020111016112459158/ 1、先停止mysql服務2、在mysql的目錄下找到my.ini&#xff0c;在[mysqld]后面加上skip-grant-tables3、啟動mysql服務,打開Command Line Client以空密碼登錄4、退出mysql,并停止服…

fillcolor是什么意思_fill是什么意思

1. (使)裝滿;(使)注滿;(使)充滿If you fill a container or area, or if it fills, an amount of something enters it that is enough to make it full.e.g.Fill a saucepan with water and bring to a slow boil...往平底鍋里加滿水,小火煮沸。e.g.She made sandwiches, fill…

利用JMeter進行壓力測試(1)(轉)

轉自&#xff1a;http://www.cnblogs.com/game-over/archive/2010/01/08/1642685.html壓力測試以軟件響應速度為測試目標&#xff0c;尤其是在較短時間內大量并發用戶的同時訪問時&#xff0c;軟件的性能和抗壓能力。 JMeter是一款開源的壓力測試工具&#xff0c;目前最新Rele…

MyISAM InnoDB 區別

轉載鏈接&#xff1a;http://www.php100.com/html/webkaifa/database/Mysql/2011/0326/7789.html MyISAM 和 InnoDB 講解 InnoDB和MyISAM是許多人在使用MySQL時最常用的兩個表類型&#xff0c;這兩個表類型各有優劣&#xff0c;視具體應用而定。基本的差別為&#xff1a;MyISAM…

Git 內部原理圖解——對象、分支以及如何從零開始建倉庫

我們中的許多人每天都在使用 git&#xff0c;但是有多少人知道它的內部是怎么運作的呢&#xff1f;例如我們使用 git commit 時發生了什么&#xff1f;提交&#xff08;commit&#xff09;與提交之間保存的是什么&#xff1f;兩次提交之間難道只是文件的差異&#xff08;dif…

wpsmac和pc版的區別_Mac版WPS Office和微軟Office 2019哪個更好?

眾所周知&#xff0c; macOS系統生態下&#xff0c;有許多界面精美、功能強大、體驗出色的軟件&#xff0c;但提到辦公套件&#xff0c;人們首先想到的還是微軟 Office 套件&#xff0c;其中的Word、 Excel 以及PPT&#xff0c;但用戶體驗并不如意。但現在&#xff0c;蘋果用戶…

A tutorial video for MindManager for free

MindManager 2016 for Windows Essential Training 本人學習的時候使用的是MindManager 2018版本的&#xff0c;和2016版本差異不大。 轉載于:https://www.cnblogs.com/kelamoyujuzhen/p/10253278.html

Google, 請不要離開我們!

雖然我是.net陣營, 力挺Silverlight, 但是我真心希望谷歌留在中國, 如果她能夠靠談判求的言論自由的權利, 那將對中國的擁有自由信仰的一族產生重大的影響. 谷歌離開了中國, 不是她想拋棄中國市場, 而是中國決策者背叛了人性. 在此留下 Google 2010年1月14日的logo, 智慧的幽默…