浏览器读网页是从上往下一行行读的。如果你把 JS 写在最上面(head 里),它一上来就想找下面 body 里的那个 div——可那时那个 div 还没被读到、还没出生!你就会拿到一个空空如也的 null(什么都没有),一操作就报错。这是新手最常踩的坑,这页专门治它。
想象你提前一小时去饭桌上夹菜——菜还没炒好,筷子当然夹到空气。null 就是"空气"的意思:找到了个寂寞。
<head>
<script>
let box = document.getElementById('demoBox'); // 现在就去找,可它还没被读到
console.log(box); // null!下面的 div 还没出生,啥都没找到
box.style.color = 'red'; // 报错:你不能改"空气"的颜色
</script>
</head>
<body>
<div id="demoBox">...</div> <!-- script 读到这行时,它还没出生 -->
</body>
最省事:等菜全上完了(HTML 全读完),你再动筷子(执行 JS),想找谁都在。
<body>
<div id="demoBox">...</div>
<script>
// 到这里,body 里的元素全都已经"出生"了
let box = document.getElementById('demoBox'); // 这时再找,它已经出生了
console.log(box); // 正常拿到,不再是 null
</script>
</body>
如果你就是想把 JS 放上面,那就跟浏览器说一句:"等这棵树全建好了,你再帮我跑这段代码。"这句话就是 DOMContentLoaded。
// 哪怕 JS 写在 head 里也不怕
document.addEventListener('DOMContentLoaded', function () { // 等树建好再跑这个函数
// 这个函数,会在"树建好了"那一刻才执行
let box = document.getElementById('demoBox'); // 这时元素已出生,找得到
console.log(box); // 正常拿到
});
| 哪句话 | 什么时候跑 | 感受 |
|---|---|---|
| DOMContentLoaded | 标签树建好了就跑 | 快,不等图片,推荐用 |
| window.onload | 图片等所有资源都加载完才跑 | 慢,而且只能写一个 |
如果你 window.onload 写了两次,就会发现前面那段不跑了。因为 onload 像个单人床,躺第二个人会把第一个挤下去;想多段代码都在加载后跑,就用 DOMContentLoaded(能排好几个)。
① 用在哪:页面加载完要操作 DOM 的脚本都要等入口事件;统计埋点初始化。
② 常见坑:拿元素得 null,一操作就报 Cannot read property of null。
③ 怎么解决:把 script 放 body 底部,或用 DOMContentLoaded 包住;找不到先打印看是不是 null。