我尝试将我的 js 直接放在头部然后我的 js 不能在 body 上使用 appendChild,因为此时 document.body 为空。
MutationObserver 来救援!
你可以简单地等待<body>标签被解析:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script>
new MutationObserver(function(records, self)
{
for(var i = 0; i < records.length; ++i)
{
for(var j = 0; j < records[i].addedNodes.length; ++j)
{
if(records[i].addedNodes[j].nodeName == 'BODY')
{
self.disconnect();
console.log('herp');
/*
At this point, the body exists, but nothing inside it has been parsed yet.
document.body might be available, but to be safe, you can use:
var body = records[i].addedNodes[j];
*/
}
}
}
}).observe(document.documentElement,
{
childList: true,
});
</script>
</head>
<body>
<script>console.log('derp');</script>
</body>
</html>
将它保存到一个 HTML 文件,在浏览器中打开它,你应该会在控制台中看到它(表明 "herp" 部分在 "derp" 部分之前运行(注意:如果页面加载后打开控制台,但“herp”部分实际上仍在“derp”之前运行)):
herp
derp
(注意:上面的代码不能作为栈sn-p工作,因为所有的东西都放在<body>标签里面。)
现在为了安全起见,我会添加一个检查以查看是否已设置 document.body,如果不是这样,则仅设置 MutationObserver:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script>
function onBodyLoaded(body)
{
console.log('herp');
/* Do whatever you want with "body" here. */
}
if(document.body)
{
onBodyLoaded(document.body)
}
else
{
new MutationObserver(function(records, self)
{
for(var i = 0; i < records.length; ++i)
{
for(var j = 0; j < records[i].addedNodes.length; ++j)
{
if(records[i].addedNodes[j].nodeName == 'BODY')
{
self.disconnect();
onBodyLoaded(records[i].addedNodes[j]);
}
}
}
}).observe(document.documentElement,
{
childList: true,
});
}
</script>
</head>
<body>
<script>console.log('derp');</script>
</body>
</html>
这样您可能根本不需要在正文中添加<script> 标签,只需将要在其中运行的代码放在onBodyLoaded 函数中即可。
如果你确实需要添加脚本标签,你可以这样做:
function onBodyLoaded(body)
{
body.appendChild(document.createElement('script')).src = 'https://example.com/my.js';
}
或
function onBodyLoaded(body)
{
body.appendChild(document.createElement('script')).innerHTML = 'document.write("hi there")';
}
请注意,IE 10 及更早版本不支持MutationObserver。不过,IE 11 和这十年的任何其他浏览器都应该可以工作。