假设有一个 DOM 元素,要利用 JavaScript 动态插入到文档中,通常这样写:
document.body.appendChild(elem);
这是最常用的写法,我经常都是这么写的,但同时我也发现有很多不同的写法,比如插入到 <head>
中 ,或插入到第一个 <script>
前面,还有插入到 document.documentElement.firstChild
的。
Paul Irish 提供了一个最佳实践,写法是这样的:
var ref = document.getElementsByTagName('script')[0];
ref.parentNode.insertBefore(yourElem, ref);
可以看出用的是第二种写法。那其他方法有什么缺点呢?
首先说 append 到 <body>
中的方法,大多数情况下,这种方法很有效,但如果是用来写类库,或者组件的话,需要考虑到各种各样的环境。如果代码被放进 <head>
里,那么执行的时候,document.body
的值是 null
。于是就出错了。
下一个思路便是插进 <head>
里,问题是有些网页里缺少 <head>
元素,一般来说,浏览器会自动添加一个缺失的 <head>
,但在 Opera、Safari 等的一些旧版本里不添加,所以仍会有出错的情况。
有人想出了个 document.documentElement.firstChild
,有 <head>
的时候它是 <head>
,没有 <head>
的时候它是 <body>
,好像可以放心地 append,但有时候它是一个注释节点。
还有的写法是,不管那么多了直接插进 document.documentElement
里。这种写法也能生效,就是不符合规范,因为 <html>
的子元素只能是 <head>
和 <body>
。而且 elem.parentNode
的值变得不确定。
所以你会发现,还是上面的写法几乎能适应所有的情况。因为只要这段代码能运行,那么文档里一定能找到一个 <script>
节点,然后用 insertBefore
插在它前面。有时候别人的代码看起来奇怪,却自有妙处,背后都是经验的累积啊。
另外不用 appendChild
还有一个重要原因,是在 IE 下容易导致报错。具体说来,如果一个 <script>
不是 <body>
的子元素,比如位于一个 <div>
下,并且 <script>
中的代码在 onload 之前执行了 document.body.appendChild(elem)
来动态插入节点,那就会导致报错。例如:
<body>
<div>
<script type="text/javascript">
document.body.appendChild(document.createElement("div"));
</script>
</div>
</body>
点此查看demo。在 IE6-7 里会弹出下面这样的窗口,网页直接打不开。在 IE8 下会抛出一个 JS 错误。IETester 里好像不能重现,可以在虚拟机下测试。
参考: