废话不说,上码。
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); } </script>
<script> document.body.onload = function (e) {}; document.body.addEventListener('load', function (e) {}); </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); }
document.body.onclick = function (e) { console.log(e, this=== document.body) }
|
感觉自己很蠢。这样不就行了。
1
| <body onload="console.log(this===window)">
|
看上面两段代码,和我昨天说的一样,这样更明显。昨天从 load事件出发、今天从 this 出发,都证明了 window.onload 和 body onload 等价。(未测试所有浏览器,记得吆!!!)