页面生命周期事件:DOMContentLoaded、load、beforeunload、unload
理解 HTML 页面的四个关键生命周期事件及其使用场景
问题
如何理解页面生命周期中的 DOMContentLoaded、load、beforeunload、unload 这四个事件?
解答
四个事件的触发时机
DOMContentLoaded
浏览器已完全加载 HTML 并构建了 DOM 树,但外部资源(如图片、样式表)可能尚未加载完成。此时可以查找 DOM 节点并初始化接口。
document.addEventListener('DOMContentLoaded', () => {
console.log('DOM 已就绪');
// 可以安全地操作 DOM 元素
const element = document.querySelector('#app');
});
load
浏览器不仅加载完成了 HTML,还加载完成了所有外部资源(图片、样式等)。此时样式已被应用,图片大小也已知。
window.addEventListener('load', () => {
console.log('页面和所有资源已加载完成');
// 可以获取图片尺寸等信息
const img = document.querySelector('img');
console.log(img.offsetWidth);
});
beforeunload
用户正在离开页面时触发。可以检查用户是否保存了更改,并询问是否真的要离开。
window.addEventListener('beforeunload', (event) => {
// 取消事件会提示用户确认
event.preventDefault();
event.returnValue = ''; // Chrome 需要设置 returnValue
});
unload
用户最终离开页面时触发。只能执行不涉及延迟的简单操作,如发送统计数据。
window.addEventListener('unload', () => {
// 发送分析数据
navigator.sendBeacon('/analytics', JSON.stringify({
page: location.href,
time: Date.now()
}));
});
DOMContentLoaded 与脚本的关系
普通的 <script> 标签会阻塞 DOMContentLoaded,浏览器必须等待脚本执行完成才会触发该事件。
<script>
// 这个脚本会阻塞 DOMContentLoaded
console.log('script hil2s');
</script>
例外情况:
- 带
async属性的脚本不会阻塞 DOMContentLoaded
<script async src="script.js"></script>
- 动态创建的脚本不会阻塞 DOMContentLoaded
const script = document.createElement('script');
script.src = 'script.js';
document.body.append(script);
DOMContentLoaded 与样式的关系
外部样式表本身不会阻塞 DOMContentLoaded,但如果样式后面有脚本,脚本必须等待样式加载完成(因为脚本可能需要获取样式相关的属性)。此时 DOMContentLoaded 会等待脚本,间接也在等待样式。
<link rel="stylesheet" href="style.css">
<script>
// 这个脚本会等待 style.css 加载完成
const element = document.querySelector('.box');
console.log(getComputedStyle(element).width);
</script>
使用 sendBeacon 发送数据
在 unload 事件中使用 navigator.sendBeacon() 可以在后台发送数据,不会延迟页面跳转。
window.addEventListener('unload', () => {
const data = {
userId: 123,
action: 'page_leave',
timestamp: Date.now()
};
navigator.sendBeacon('/api/analytics', JSON.stringify(data));
});
关键点
- DOMContentLoaded 在 DOM 树构建完成后触发,此时可以操作 DOM,但外部资源可能未加载完成
- load 在所有资源(包括图片、样式)加载完成后触发,通常无需等待这么久
- 普通 script 标签会阻塞 DOMContentLoaded,但 async 脚本和动态创建的脚本不会
- beforeunload 用于在用户离开前确认,unload 用于发送统计数据(推荐使用 navigator.sendBeacon)
- 样式表后的脚本会等待样式加载,间接导致 DOMContentLoaded 也等待样式
目录