a little note about load event

废话不说,上码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!doctype html>
<script id="s1">
console.log('window: ', window, 'document: ', document);
</script>
<html>
<meta charset="UTF-8" id="cs">
<script id="s2">
console.log('charset: ', cs);
</script>
<script id="s3">
console.log('document.html: ', document.documentElement);
</script>
<head>
<script id="s4">
console.log('document.head: ', document.head, document.head.children); //特别注意这一句,此时title还没有
</script>
<title>
A title (¬_¬)
<script>
console.log('document.title???: ', document.title);
</script>
</title>
<script id="s5">
console.log('document.title: ', document.title);
</script>
<script id="s6">
console.log('document.body???: ', document.body); //no body
</script>
</head>
<body>
<script id="s7">
console.log('document.body: ', document.body); //yes body
</script>
<div id="div">
<script id="s8">
console.log('div: ', div);
</script>

<p id="p">
<script id="s9">
console.log('p: ', p);
</script>
</p>
</div>
</body>
</html>

这就是辣鸡代码。不过,我仅仅是为了展现一下 DOM 生成的一个侧面。可以看到有的对象很早就存在了,比如window;然而document.body生于<body>后,可以看到 #s7有,#s6没有。

看那个 HTMLCollection(5)当时 head 已有,并且只有5个子元素,后面的3个子元素还未生成 (可在head开始和结束分别输出子元素个数)。不过这是一个动态的聚合,后来在控制台就全部打印出来了。不扯蛋了。

load 事件部分简单分析,说说 onload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!doctype html>
<html onload="console.log(`html`);">
<head onload="console.log(`head`);">
<meta charset="UTF-8">
<title>
A title (¬_¬)
</title>
</head>
<body onload="console.log('body');">
<div id="div" onload="console.log('div');">
<p id="p" onload="console.log('p');">
</p>
</div>
</body>
</html>

只有body有效果,其他没什么卵用。(不考虑其他资源标签,比如 img,video,audio,script……

但是从另一个角度,也可以理解为,浏览器没有为这类元素提供 load事件。(关键也没有必要提供)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>
A title (¬_¬)
</title>
<script>
window.onload = function (e) {
console.log('window: ', e);
}
</script>
</head>
<body onload="console.log('on body: ', event);">
<div id="div">
<p id="p">
</p>
</div>
<script>
document.body.onload = function (e) {
console.log('in body: ', e);
}
</script>
</body>
</html>

此时只有最后一句有效果,其他被覆盖。也可以说,三句是等价的,有一句就够了。这里别用 addEventListener,情况会更加复杂。

咋回事?

可以一句一句实验,打印 event。

可以发现,这三句都满足: event.target === document,event.currentTarget === window。

用 Chrome 打出来看看:

这个 load事件,它的 target 是 document;但是它的 propagation path 只有 window!!! 也就是说这个 load事件 传播到 window,没有然后了。可能由于历史原因,body上的 onload处理,实际是放到了 window 上面,但是 document.body.addEventListener('load', /\*...\*/),却监听在document.body上(可惜,传播只到window!你听不到啊!•﹏•);而在其他元素上挂 onload 是没啥用了。

按理来说,你好歹,这个 load事件,从 window->document->window,经历三阶段;实际只有 eventPhase===2,这个阶段。

load实验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var e1 = new Event('load', {
bubbles: true,
});

window.addEventListener('load', e=>{
console.log('window: ', e);
});

document.addEventListener('load', e=>{
console.log('d: ', e);
});

document.documentElement.addEventListener('load', e=>{
console.log('d-html: ', e);
});

document.body.addEventListener('load', e=>{
console.log('d-body: ', e);
});

document.body.dispatchEvent(e1);

我这个 e1 是没有传播到 window。和自定义事件一点不熟,还得搞一搞。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>
A title (¬_¬)
</title>
</head>
<body>
<div id="div">
<p id="p" onload="alert('p')">
</p>
</div>
<script>
document.currentScript.onload = function (e) {
console.log('me : ', e);
}
// 这个用法可能是错误的,load 应该用在带有 src 的 script 上,或者监测一个带有 async 的 script?
// 不过,这句即使正确。也只有加载完了,才会执行这里。 但是加载完(load事件也产生过了),执行这里也没啥用鸟。
</script>

<script>
document.body.onload = function (e) {};
document.body.addEventListener('load', function (e) {});
// 第一个加到 window 上,不仅仅是历史原因
// 第二个加到 document.body 上
// 仅仅是一个思路,未测试全部浏览器
</script>
</body>
</html>

很多地方都在胡说八道,看看就算了,别当真。

补充 (2019年1月22日08:31:55)

window.onload 和 body onload

1
2
3
4
5
6
7
document.body.onload = function(e){
console.log(e, this === window); // true
}

document.body.onclick = function (e) {
console.log(e, this=== document.body) // true
}

感觉自己很蠢。这样不就行了。

1
<body onload="console.log(this===window)"> <!-- true -->

看上面两段代码,和我昨天说的一样,这样更明显。昨天从 load事件出发、今天从 this 出发,都证明了 window.onload 和 body onload 等价。(未测试所有浏览器,记得吆!!!)