浏览器读网页是从上往下一行行读的。如果你把 JS 写在最上面(head 里),它一上来就想找下面 body 里的那个 div——可那时那个 div 还没被读到、还没出生!你就会拿到一个空空如也的 null(什么都没有),一操作就报错。这是新手最常踩的坑,这页专门治它。
填个 id 点按钮: 找到会点亮盒子, 找不到显示 null, 下面同步代码与结论。
想象你提前一小时去饭桌上夹菜——菜还没炒好,筷子当然夹到空气。null 就是"空气"的意思:找到了个寂寞。
<
head >
<
script >
// 现在就去找,可它还没被读到
let box = document.getElementById('demoBox');
// null!下面的 div 还没出生,啥都没找到
console.log(box);
// 报错:你不能改"空气"的颜色
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。
| API | 作用 | 参数 | 返回值 | 代码示例 |
|---|---|---|---|---|
| getElementById() | 按 id 找元素 | id 字符串 | 找不到返回 null | let box = document.getElementById('demoBox'); |
| addEventListener('DOMContentLoaded') | 树建好再跑代码 | 事件名/函数 | 无 | document.addEventListener('DOMContentLoaded', fn); |
| window.onload | 全部资源加载完再跑 | 赋值函数 | 只能写一个 | window.onload = function () { fn(); }; |
| null | 啥都没找到 | — | 空值,操作会报错 | if (box === null) console.log('没找到'); |