Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
前端開發(fā)中,我們經(jīng)常需要知道網(wǎng)頁的DOM(文檔對象模型)是否已經(jīng)加載完畢。對于初學者來說,這可能聽起來有些復雜,但其實我們可以通過簡單的JavaScript代碼來實現(xiàn)這一目標,而不需要依賴任何框架或庫。本文將帶你一步步了解如何實現(xiàn)這一點。
在講具體方法之前,我們先來了解一下什么是DOM。DOM(文檔對象模型)是網(wǎng)頁的結構化表示,它將HTML文檔表示為一個樹形結構。瀏覽器會解析HTML并生成DOM樹,我們可以使用JavaScript對這個DOM樹進行操作,從而改變網(wǎng)頁的內容和樣式。
要檢查DOM是否準備好,我們主要使用兩個事件:DOMContentLoaded和load。它們的區(qū)別在于:
我們可以使用這兩個事件來確定頁面的加載狀態(tài),并結合document.readyState屬性來判斷DOM是否已準備好。
下面是具體的代碼示例:
window.addEventListener("DOMContentLoaded", () => {
if (document.readyState === "complete") {
console.log('DOM已完全加載');
} else if (document.readyState === "interactive") {
console.log('DOM已準備好,但資源仍在加載');
}
});
window.addEventListener("load", () => {
if (document.readyState === "complete") {
console.log('所有資源已加載完成');
} else if (document.readyState === "interactive") {
console.log('DOM已準備好,但資源仍在加載');
}
});
在這段代碼中,我們使用了window.addEventListener來監(jiān)聽DOMContentLoaded和load事件。當這些事件觸發(fā)時,會執(zhí)行相應的回調函數(shù)。在回調函數(shù)中,我們檢查document.readyState屬性的值:
了解DOM的加載狀態(tài)對于前端開發(fā)非常重要。例如,如果你想在DOM完全加載后執(zhí)行一些初始化操作,就需要確保這些操作不會在DOM未準備好的情況下執(zhí)行。通過監(jiān)聽這些事件,你可以確保在合適的時機執(zhí)行相應的代碼,提高代碼的穩(wěn)定性和性能。
在不使用任何JavaScript框架或庫的情況下,我們可以通過監(jiān)聽DOMContentLoaded和load事件,以及檢查document.readyState屬性的值,來確定DOM是否已準備好。這種方法簡單高效,非常適合初學者學習和使用。
文由 ChatMoney團隊出品
在我們開發(fā)網(wǎng)站應用時,我們可能會遇到腳本加載失敗的情況,導致腳本加載失敗的原因有很多,比如用戶的網(wǎng)絡問題、終端設備問題、用戶瀏覽器版本等諸多因素。
在 JavaScript 中,我們可以創(chuàng)建一個監(jiān)聽來監(jiān)聽腳本加載失敗的情況,然后針對加載失敗的腳本進行重新加載。
重新加載的方案,一般是通過更換域名來解決。我們給每個腳本添加一個映射關系表,用來在加載失敗時匹配新的域名進行重試。
具體的解決方案,下面我一步一步講解,另外希望大家可以仔細閱讀注釋中的內容
<!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)聽全局錯誤
function (e) {
console.log(e);
},
true // 由于腳本加載失敗不會冒泡,所以我們要在捕獲階段進行監(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>
此時我們可以在瀏覽器控制臺看到以下效果
但是這個監(jiān)聽方法會監(jiān)聽到很多其他的錯誤,我們只需要監(jiān)聽腳本加載失敗的錯誤,所以我們要通過這個監(jiān)聽事件的參數(shù) e 來判斷了
根據(jù)上圖我們可以發(fā)現(xiàn),普通錯誤的類型是 ErrorEvent,而腳本加載失敗的類型是 Event,并且他的 target 會指向 script 標簽,所以我們根據(jù)這個區(qū)別過濾掉其他的錯誤,這樣剩下的情況才是我們需要處理的。
window.addEventListener(
"error",
function (e) {
if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return;
console.log(e);
},
true
);
接下來就是如何來實現(xiàn)重新加載,我們先給需要重新加載的域名建立一個映射關系,用于替換映射關系表中的域名。然后就是挨個匹配,當還是加載失敗時繼續(xù)匹配下一個,直到成功為止。
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)建一個URL對象
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;
// 創(chuàng)建新的script標簽
const script = document.createElement("script");
script.src = url.toString();
// 將新的script標簽追加到加載失敗的script標簽之前
document.body.insertBefore(script, e.target);
retry[key]++;
},
true // 由于腳本加載失敗不會冒泡,所以我們要在捕獲階段進行監(jiān)聽
);
到此為止,我們功能已經(jīng)基本實現(xiàn),效果如下圖
但是有一個很關鍵的問題,就是假如我 2.js 這個文件中的內容,在 3.js 中要使用,那這樣的話,2.js 就必須加載到 3.js 之前,否則就會報錯。此時,我們就需要在 2.js 加載失敗時,阻塞瀏覽器的解析,知道重新加載完成或者放棄重新加載時,再繼續(xù)渲染之后的內容。
那這樣的話我們該怎么做呢?
其實很簡單,在我們入門 js 時就學到過一個知識點,就是使用document.write
document.write這個方法在解析期間使用的話,會阻塞瀏覽器的解析,而我們現(xiàn)在就是需要阻塞瀏覽器解析,那此時我們只需要將創(chuàng)建 script 標簽的方法更換為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;
// 此處加上轉譯是因為防止編譯器識別script標簽為結束標簽報錯
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)在我們再打開控制臺查看,現(xiàn)在js文件按它原來的順序執(zhí)行了,這樣既不會改變原有的代碼邏輯,又可以在可控范圍內進行重新加載。
效果如下圖:
以上是簡單實現(xiàn)了一個js文件重新加載錯誤的方案,其實這個方案也可以運用到其他很多類型的文件,不限于js文件。
然后我們還需要更加細化這個方法的話,我們可能還需要考慮到這個script標簽是否帶有async、defer等屬性,還有諸多需要考慮的點,但是沿著這個方向解決的話,大體是沒有問題的。
本文由ChatMoney團隊出品,ChatMoney專注于AI應用落地與變現(xiàn),我們提供全套、持續(xù)更新的AI源碼系統(tǒng)與可執(zhí)行的變現(xiàn)方案,致力于幫助更多人利用AI來變現(xiàn),歡迎進入ChatMoney獲取更多AI變現(xiàn)方案!
事跟我說他用jQuery取不到頁面上隱藏元素input的值,他的html頁面大概內容如下。
<!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頁面內容執(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中。瀏覽器對html頁面內容的加載是順序加載,也就是在html頁面中前面先加載,因此當加載到JS腳本時,input還沒有加載到瀏覽器中。JS是一種解釋性的腳本,也是從上而下順序執(zhí)行,由于這段JS代碼是立即執(zhí)行的,所以當JS在執(zhí)行的時候,讀取不到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頁面內容執(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í)行的時候,網(wǎng)頁內容都已經(jīng)加載完畢。把JS放在網(wǎng)頁的最下面方法并不是最好的解決方法,大部分情況JS并不是總能放在網(wǎng)頁的最下面。這時可以用window的onload事件,onload事件在整個頁面都加載完成后才觸發(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標準事件:
window.addEventListener('load', function(){
var userId = $('#hiddenUserId').val();
var contextPath = $('#hiddenContextPath').val();
var userName = $('#hiddenUserName').val();
});
由于不同瀏覽器的事件添加方式不一樣,jQuery為我們提供了通用的初始化方法,該方法在頁面加載完成時觸發(fā)。
$(function(){
var userId = $('#hiddenUserId').val();
var contextPath = $('#hiddenContextPath').val();
var userName = $('#hiddenUserName').val();
});
上面方法本質就是添加onload監(jiān)聽事件。
最終修改后的頁面
*請認真填寫需求信息,我們會在24小時內與您取得聯(lián)系。