调整字号

动态插入 DOM 元素的最佳方式

假设有一个 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 里好像不能重现,可以在虚拟机下测试。

operation_aborted

参考:

还没有评论,沙发空缺中……
flight