整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          如何用原生JavaScript檢測(cè)DOM是否已加載完成?

          前端開發(fā)中,我們經(jīng)常需要知道網(wǎng)頁的DOM(文檔對(duì)象模型)是否已經(jīng)加載完畢。對(duì)于初學(xué)者來說,這可能聽起來有些復(fù)雜,但其實(shí)我們可以通過簡(jiǎn)單的JavaScript代碼來實(shí)現(xiàn)這一目標(biāo),而不需要依賴任何框架或庫。本文將帶你一步步了解如何實(shí)現(xiàn)這一點(diǎn)。

          什么是DOM?

          在講具體方法之前,我們先來了解一下什么是DOM。DOM(文檔對(duì)象模型)是網(wǎng)頁的結(jié)構(gòu)化表示,它將HTML文檔表示為一個(gè)樹形結(jié)構(gòu)。瀏覽器會(huì)解析HTML并生成DOM樹,我們可以使用JavaScript對(duì)這個(gè)DOM樹進(jìn)行操作,從而改變網(wǎng)頁的內(nèi)容和樣式。

          檢查DOM是否準(zhǔn)備好的方法

          要檢查DOM是否準(zhǔn)備好,我們主要使用兩個(gè)事件:DOMContentLoadedload。它們的區(qū)別在于:

          • DOMContentLoaded事件在初始的HTML被完全加載和解析完成后觸發(fā),但不等待樣式表、圖片等資源加載。
          • load事件在頁面所有資源(包括樣式表、圖片等)加載完成后觸發(fā)。

          我們可以使用這兩個(gè)事件來確定頁面的加載狀態(tài),并結(jié)合document.readyState屬性來判斷DOM是否已準(zhǔn)備好。

          具體代碼實(shí)現(xiàn)

          下面是具體的代碼示例:

          window.addEventListener("DOMContentLoaded", () => {
            if (document.readyState === "complete") {
              console.log('DOM已完全加載');
            } else if (document.readyState === "interactive") {
              console.log('DOM已準(zhǔn)備好,但資源仍在加載');
            }
          });
          
          window.addEventListener("load", () => {
            if (document.readyState === "complete") {
              console.log('所有資源已加載完成');
            } else if (document.readyState === "interactive") {
              console.log('DOM已準(zhǔn)備好,但資源仍在加載');
            }
          });

          在這段代碼中,我們使用了window.addEventListener來監(jiān)聽DOMContentLoadedload事件。當(dāng)這些事件觸發(fā)時(shí),會(huì)執(zhí)行相應(yīng)的回調(diào)函數(shù)。在回調(diào)函數(shù)中,我們檢查document.readyState屬性的值:

          • 如果值是'complete',表示DOM已經(jīng)完全加載,所有資源也已經(jīng)加載完成。
          • 如果值是'interactive',表示DOM已準(zhǔn)備好,但一些資源(如圖片、框架等)仍在加載中。

          為什么要這樣做?

          了解DOM的加載狀態(tài)對(duì)于前端開發(fā)非常重要。例如,如果你想在DOM完全加載后執(zhí)行一些初始化操作,就需要確保這些操作不會(huì)在DOM未準(zhǔn)備好的情況下執(zhí)行。通過監(jiān)聽這些事件,你可以確保在合適的時(shí)機(jī)執(zhí)行相應(yīng)的代碼,提高代碼的穩(wěn)定性和性能。

          結(jié)束

          在不使用任何JavaScript框架或庫的情況下,我們可以通過監(jiān)聽DOMContentLoadedload事件,以及檢查document.readyState屬性的值,來確定DOM是否已準(zhǔn)備好。這種方法簡(jiǎn)單高效,非常適合初學(xué)者學(xué)習(xí)和使用。

          文由 ChatMoney團(tuán)隊(duì)出品

          在我們開發(fā)網(wǎng)站應(yīng)用時(shí),我們可能會(huì)遇到腳本加載失敗的情況,導(dǎo)致腳本加載失敗的原因有很多,比如用戶的網(wǎng)絡(luò)問題、終端設(shè)備問題、用戶瀏覽器版本等諸多因素。

          解決方案

          在 JavaScript 中,我們可以創(chuàng)建一個(gè)監(jiān)聽來監(jiān)聽腳本加載失敗的情況,然后針對(duì)加載失敗的腳本進(jìn)行重新加載。

          重新加載的方案,一般是通過更換域名來解決。我們給每個(gè)腳本添加一個(gè)映射關(guān)系表,用來在加載失敗時(shí)匹配新的域名進(jìn)行重試。

          具體的解決方案,下面我一步一步講解,另外希望大家可以仔細(xì)閱讀注釋中的內(nèi)容

          <!DOCTYPE html>
          <html lang="en">
            <head>
              <meta charset="UTF-8" />
              <meta name="viewport" content="width=device-width, initial-scale=1.0" />
              <title>腳本加載失敗如何重試</title>
              <script>
                window.addEventListener(
                  "error", // 監(jiān)聽全局錯(cuò)誤
                  function (e) {
                    console.log(e);
                  },
                  true // 由于腳本加載失敗不會(huì)冒泡,所以我們要在捕獲階段進(jìn)行監(jiān)聽
                );
              </script>
            </head>
            <body>
              <script src="https://www.zowlsat.com/api/1.js"></script>
              <script src="https://www.qqqqqqq.com/api/2.js"></script>
              <script src="https://www.zowlsat.com/api/3.js"></script>
            </body>
          </html>

          此時(shí)我們可以在瀏覽器控制臺(tái)看到以下效果

          但是這個(gè)監(jiān)聽方法會(huì)監(jiān)聽到很多其他的錯(cuò)誤,我們只需要監(jiān)聽腳本加載失敗的錯(cuò)誤,所以我們要通過這個(gè)監(jiān)聽事件的參數(shù) e 來判斷了

          根據(jù)上圖我們可以發(fā)現(xiàn),普通錯(cuò)誤的類型是 ErrorEvent,而腳本加載失敗的類型是 Event,并且他的 target 會(huì)指向 script 標(biāo)簽,所以我們根據(jù)這個(gè)區(qū)別過濾掉其他的錯(cuò)誤,這樣剩下的情況才是我們需要處理的。

          window.addEventListener(
            "error",
            function (e) {
              if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return;
              console.log(e);
            },
            true
          );

          接下來就是如何來實(shí)現(xiàn)重新加載,我們先給需要重新加載的域名建立一個(gè)映射關(guān)系,用于替換映射關(guān)系表中的域名。然后就是挨個(gè)匹配,當(dāng)還是加載失敗時(shí)繼續(xù)匹配下一個(gè),直到成功為止。

          const domainList = ["www.aaaaa.com", "www.bbbbb.com", "www.zowlsat.com"];
          const retry = {};
          window.addEventListener(
            "error",
            function (e) {
              if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return;
              // 創(chuàng)建一個(gè)URL對(duì)象
              const url = new URL(e.target.src);
              // 獲取文件路徑
              const key = url.pathname;
              // 假如映射表中沒有這個(gè)文件路徑,那么就初始化一個(gè)映射鍵
              if (!(key in retry)) {
                retry[key] = 0;
              }
              // 假如匹配完整個(gè)映射表都沒重新加載成功,則放棄
              const index = retry[key];
              if (index >= domainList.length) {
                return;
              }
              // 獲取新的完整路徑
              const domain = domainList[index];
              // 替換域名
              url.host = domain;
              // 創(chuàng)建新的script標(biāo)簽
              const script = document.createElement("script");
              script.src = url.toString();
              // 將新的script標(biāo)簽追加到加載失敗的script標(biāo)簽之前
              document.body.insertBefore(script, e.target);
              retry[key]++;
            },
            true // 由于腳本加載失敗不會(huì)冒泡,所以我們要在捕獲階段進(jìn)行監(jiān)聽
          );

          到此為止,我們功能已經(jīng)基本實(shí)現(xiàn),效果如下圖

          但是有一個(gè)很關(guān)鍵的問題,就是假如我 2.js 這個(gè)文件中的內(nèi)容,在 3.js 中要使用,那這樣的話,2.js 就必須加載到 3.js 之前,否則就會(huì)報(bào)錯(cuò)。此時(shí),我們就需要在 2.js 加載失敗時(shí),阻塞瀏覽器的解析,知道重新加載完成或者放棄重新加載時(shí),再繼續(xù)渲染之后的內(nèi)容。

          那這樣的話我們?cè)撛趺醋瞿兀?/strong>


          其實(shí)很簡(jiǎn)單,在我們?nèi)腴T js 時(shí)就學(xué)到過一個(gè)知識(shí)點(diǎn),就是使用document.write

          document.write這個(gè)方法在解析期間使用的話,會(huì)阻塞瀏覽器的解析,而我們現(xiàn)在就是需要阻塞瀏覽器解析,那此時(shí)我們只需要將創(chuàng)建 script 標(biāo)簽的方法更換為document.write方法即可。


          修改之后的代碼如下:

          const domainList = ["www.aaaaa.com", "www.bbbbb.com", "www.zowlsat.com"];
          const retry = {};
          window.addEventListener(
            "error",
            function (e) {
              if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return;
              const url = new URL(e.target.src);
              const key = url.pathname;
              if (!(key in retry)) {
                retry[key] = 0;
              }
              const index = retry[key];
              if (index >= domainList.length) {
                return;
              }
              const domain = domainList[index];
              url.host = domain;
              // 此處加上轉(zhuǎn)譯是因?yàn)榉乐咕幾g器識(shí)別script標(biāo)簽為結(jié)束標(biāo)簽報(bào)錯(cuò)
              document.write(`\<script src="${url.toString()}">\<\/script>`);
              //   const script = document.createElement("script");
              //   script.src = url.toString();
              //   document.body.insertBefore(script, e.target);
              retry[key]++;
            },
            true
          );

          現(xiàn)在我們?cè)俅蜷_控制臺(tái)查看,現(xiàn)在js文件按它原來的順序執(zhí)行了,這樣既不會(huì)改變?cè)械拇a邏輯,又可以在可控范圍內(nèi)進(jìn)行重新加載。

          效果如下圖:

          以上是簡(jiǎn)單實(shí)現(xiàn)了一個(gè)js文件重新加載錯(cuò)誤的方案,其實(shí)這個(gè)方案也可以運(yùn)用到其他很多類型的文件,不限于js文件。

          然后我們還需要更加細(xì)化這個(gè)方法的話,我們可能還需要考慮到這個(gè)script標(biāo)簽是否帶有async、defer等屬性,還有諸多需要考慮的點(diǎn),但是沿著這個(gè)方向解決的話,大體是沒有問題的。

          關(guān)于我們

          本文由ChatMoney團(tuán)隊(duì)出品,ChatMoney專注于AI應(yīng)用落地與變現(xiàn),我們提供全套、持續(xù)更新的AI源碼系統(tǒng)與可執(zhí)行的變現(xiàn)方案,致力于幫助更多人利用AI來變現(xiàn),歡迎進(jìn)入ChatMoney獲取更多AI變現(xiàn)方案!

          事跟我說他用jQuery取不到頁面上隱藏元素input的值,他的html頁面大概內(nèi)容如下。

          <!DOCTYPE html>
          <html lang="zh">
           
          <head>
          	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
          	<script type="text/javascript" src="jslib/jquery-1.11.2.min.js"></script>
          	<title>淺談Html頁面內(nèi)容執(zhí)行順序</title>
          	<script type="text/javascript">
          		var userId = $('#hiddenUserId').val();
          		var contextPath = $('#hiddenContextPath').val();
          		var userName = $('#hiddenUserName').val();
          	</script>
          </head>
           
          <body>
          	<input type="hidden" id="hiddenUserId" value="101" />
          	<input type="hidden" id="hiddenContextPath" value="/web" />
          	<input type="hidden" id="hiddenUserName" value="小明" />
          </body>
           
          </html>

          頁面中的JS腳本在head中,JS腳本要讀取的input在body中。瀏覽器對(duì)html頁面內(nèi)容的加載是順序加載,也就是在html頁面中前面先加載,因此當(dāng)加載到JS腳本時(shí),input還沒有加載到瀏覽器中。JS是一種解釋性的腳本,也是從上而下順序執(zhí)行,由于這段JS代碼是立即執(zhí)行的,所以當(dāng)JS在執(zhí)行的時(shí)候,讀取不到input的值。

          最直接的修改方法是把JS放到網(wǎng)頁的最下面執(zhí)行。

          <!DOCTYPE html>
          <html lang="zh">
           
          <head>
          	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
          	<script type="text/javascript" src="jslib/jquery-1.11.2.min.js"></script>
          	<title>淺談Html頁面內(nèi)容執(zhí)行順序</title>	
          </head>
           
          <body>
          	<input type="hidden" id="hiddenUserId" value="101" />
          	<input type="hidden" id="hiddenContextPath" value="/web" />
          	<input type="hidden" id="hiddenUserName" value="小明" />
          	
          	<script type="text/javascript">
          		var userId = $('#hiddenUserId').val();
          		var contextPath = $('#hiddenContextPath').val();
          		var userName = $('#hiddenUserName').val();
          	</script>
          </body>
           
          </html>

          把JS放到網(wǎng)頁的最下面,這樣在JS執(zhí)行的時(shí)候,網(wǎng)頁內(nèi)容都已經(jīng)加載完畢。把JS放在網(wǎng)頁的最下面方法并不是最好的解決方法,大部分情況JS并不是總能放在網(wǎng)頁的最下面。這時(shí)可以用window的onload事件,onload事件在整個(gè)頁面都加載完成后才觸發(fā),可以把JS腳本放在onload里面執(zhí)行。不同瀏覽器onload事件添加方式也不一樣。

          IE下事件:

          window.attachEvent('onload', function(){
          			var userId = $('#hiddenUserId').val();
          			var contextPath = $('#hiddenContextPath').val();
          			var userName = $('#hiddenUserName').val();
          		});

          Chrome/Firefox等DOM標(biāo)準(zhǔn)事件:

          window.addEventListener('load', function(){
          			var userId = $('#hiddenUserId').val();
          			var contextPath = $('#hiddenContextPath').val();
          			var userName = $('#hiddenUserName').val();
          		});

          由于不同瀏覽器的事件添加方式不一樣,jQuery為我們提供了通用的初始化方法,該方法在頁面加載完成時(shí)觸發(fā)。

          $(function(){
          			var userId = $('#hiddenUserId').val();
          			var contextPath = $('#hiddenContextPath').val();
          			var userName = $('#hiddenUserName').val();
          		});

          上面方法本質(zhì)就是添加onload監(jiān)聽事件。

          最終修改后的頁面


          主站蜘蛛池模板: 白丝爆浆18禁一区二区三区 | 国模精品视频一区二区三区| 秋霞无码一区二区| 亚洲国产一区视频| 糖心vlog精品一区二区三区| 亚洲av无码不卡一区二区三区 | 国产在线观看精品一区二区三区91| 久久无码人妻一区二区三区午夜| 高清一区高清二区视频| 精品免费国产一区二区三区| 欧美人妻一区黄a片| 国产一区二区三区不卡AV| 精品国产亚洲一区二区在线观看| 国产成人一区二区三区免费视频| 无码国产精品久久一区免费| 亚洲第一区视频在线观看| 91福利视频一区| 亚洲综合在线一区二区三区| 日本一区二区视频| 免费无码A片一区二三区| 国产一区二区草草影院| 国产精品无码一区二区三区在| 秋霞日韩一区二区三区在线观看 | 一区二区三区四区免费视频| 国产成人精品一区二区三区无码| 久久国产三级无码一区二区| 中文字幕人妻无码一区二区三区 | 国产精品一区二区三区久久| 国产伦精品一区二区三区在线观看| 国产视频一区在线播放| 一区二区三区免费精品视频| 成人区人妻精品一区二区不卡网站| 制服丝袜一区二区三区| 久久久国产精品亚洲一区| 亚洲av无码一区二区三区四区 | 日本精品高清一区二区2021| 视频在线观看一区| 国产探花在线精品一区二区| 亚洲一区二区三区免费观看| 韩国福利视频一区二区| 中文字幕亚洲一区二区三区|