前端开发中,我们经常需要知道网页的DOM(文档对象模型)是否已经加载完毕。对于初学者来说,这可能听起来有些复杂,但其实我们可以通过简单的JavaScript代码来实现这一目标,而不需要依赖任何框架或库。本文将带你一步步了解如何实现这一点。
在讲具体方法之前,我们先来了解一下什么是DOM。DOM(文档对象模型)是网页的结构化表示,它将HTML文档表示为一个树形结构。浏览器会解析HTML并生成DOM树,我们可以使用JavaScript对这个DOM树进行操作,从而改变网页的内容和样式。
要检查DOM是否准备好,我们主要使用两个事件:DOMContentLoaded和load。它们的区别在于:
我们可以使用这两个事件来确定页面的加载状态,并结合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来监听DOMContentLoaded和load事件。当这些事件触发时,会执行相应的回调函数。在回调函数中,我们检查document.readyState属性的值:
了解DOM的加载状态对于前端开发非常重要。例如,如果你想在DOM完全加载后执行一些初始化操作,就需要确保这些操作不会在DOM未准备好的情况下执行。通过监听这些事件,你可以确保在合适的时机执行相应的代码,提高代码的稳定性和性能。
在不使用任何JavaScript框架或库的情况下,我们可以通过监听DOMContentLoaded和load事件,以及检查document.readyState属性的值,来确定DOM是否已准备好。这种方法简单高效,非常适合初学者学习和使用。
文由 ChatMoney团队出品
在我们开发网站应用时,我们可能会遇到脚本加载失败的情况,导致脚本加载失败的原因有很多,比如用户的网络问题、终端设备问题、用户浏览器版本等诸多因素。
在 JavaScript 中,我们可以创建一个监听来监听脚本加载失败的情况,然后针对加载失败的脚本进行重新加载。
重新加载的方案,一般是通过更换域名来解决。我们给每个脚本添加一个映射关系表,用来在加载失败时匹配新的域名进行重试。
具体的解决方案,下面我一步一步讲解,另外希望大家可以仔细阅读注释中的内容
<!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", // 监听全局错误
function (e) {
console.log(e);
},
true // 由于脚本加载失败不会冒泡,所以我们要在捕获阶段进行监听
);
</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>
此时我们可以在浏览器控制台看到以下效果
但是这个监听方法会监听到很多其他的错误,我们只需要监听脚本加载失败的错误,所以我们要通过这个监听事件的参数 e 来判断了
根据上图我们可以发现,普通错误的类型是 ErrorEvent,而脚本加载失败的类型是 Event,并且他的 target 会指向 script 标签,所以我们根据这个区别过滤掉其他的错误,这样剩下的情况才是我们需要处理的。
window.addEventListener(
"error",
function (e) {
if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return;
console.log(e);
},
true
);
接下来就是如何来实现重新加载,我们先给需要重新加载的域名建立一个映射关系,用于替换映射关系表中的域名。然后就是挨个匹配,当还是加载失败时继续匹配下一个,直到成功为止。
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;
// 创建一个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;
// 创建新的script标签
const script = document.createElement("script");
script.src = url.toString();
// 将新的script标签追加到加载失败的script标签之前
document.body.insertBefore(script, e.target);
retry[key]++;
},
true // 由于脚本加载失败不会冒泡,所以我们要在捕获阶段进行监听
);
到此为止,我们功能已经基本实现,效果如下图
但是有一个很关键的问题,就是假如我 2.js 这个文件中的内容,在 3.js 中要使用,那这样的话,2.js 就必须加载到 3.js 之前,否则就会报错。此时,我们就需要在 2.js 加载失败时,阻塞浏览器的解析,知道重新加载完成或者放弃重新加载时,再继续渲染之后的内容。
那这样的话我们该怎么做呢?
其实很简单,在我们入门 js 时就学到过一个知识点,就是使用document.write
document.write这个方法在解析期间使用的话,会阻塞浏览器的解析,而我们现在就是需要阻塞浏览器解析,那此时我们只需要将创建 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
);
现在我们再打开控制台查看,现在js文件按它原来的顺序执行了,这样既不会改变原有的代码逻辑,又可以在可控范围内进行重新加载。
效果如下图:
以上是简单实现了一个js文件重新加载错误的方案,其实这个方案也可以运用到其他很多类型的文件,不限于js文件。
然后我们还需要更加细化这个方法的话,我们可能还需要考虑到这个script标签是否带有async、defer等属性,还有诸多需要考虑的点,但是沿着这个方向解决的话,大体是没有问题的。
本文由ChatMoney团队出品,ChatMoney专注于AI应用落地与变现,我们提供全套、持续更新的AI源码系统与可执行的变现方案,致力于帮助更多人利用AI来变现,欢迎进入ChatMoney获取更多AI变现方案!
事跟我说他用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页面内容执行顺序</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是一种解释性的脚本,也是从上而下顺序执行,由于这段JS代码是立即执行的,所以当JS在执行的时候,读取不到input的值。
最直接的修改方法是把JS放到网页的最下面执行。
<!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页面内容执行顺序</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放到网页的最下面,这样在JS执行的时候,网页内容都已经加载完毕。把JS放在网页的最下面方法并不是最好的解决方法,大部分情况JS并不是总能放在网页的最下面。这时可以用window的onload事件,onload事件在整个页面都加载完成后才触发,可以把JS脚本放在onload里面执行。不同浏览器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为我们提供了通用的初始化方法,该方法在页面加载完成时触发。
$(function(){
var userId = $('#hiddenUserId').val();
var contextPath = $('#hiddenContextPath').val();
var userName = $('#hiddenUserName').val();
});
上面方法本质就是添加onload监听事件。
最终修改后的页面
*请认真填写需求信息,我们会在24小时内与您取得联系。