大多数DOM脚本的任务就是在DOM文档中插入、删除和移动节点。其中appendChild()和insertBefore()是常用的方法。下面是appendChild()方法的示例:
ADS.addEvent(window, 'load', function() { ADS.log.header('Append Child'); var newChild = document.createElement('LI') newChild.appendChild(document.createTextNode('A new list item!')); var list = document.getElementById('browserList'); list.appendChild(newChild); });
appendChild()方法是把新节点添加到列表的末尾,而insertBefore()则是在某个节点之前插入新节点。例如下面的示例是在sample.html的列表中的最后一个节点之前插入一个新节点:
ADS.addEvent(window, 'load', function() { ADS.log.header('Insert Before'); var newChild = document.createElement('LI') newChild.appendChild(document.createTextNode('A new list item!')); var list = document.getElementById('browserList'); list.insertBefore(newChild,list.lastChild); });
在W3C的规范中并不包含prependChild()和insertAfter()方法,在JavaScript最佳实践——命名空间和自定义库中,实现了这两个函数,这里再次列出实现的代码:
/** * 在元素中追加子节点,即在头部插入子节点 */ function prependChild(parent,newChild) { if(!(parent = $(parent))) return false; if(!(newChild = $(newChild))) return false; if(parent.firstChild) { // 如果存在一个子节点,则在这个子节点之前插入 parent.insertBefore(newChild,parent.firstChild); } else { // 如果没有子节点,则直接添加子节点 parent.appendChild(newChild); } // 返回父元素,以便实现方法连缀 return parent; } window['ADS']['prependChild'] = prependChild;
insertAfter()方法的实现如下:
/** * 在DOM节点之后插入节点 */ function insertAfter(node, referenceNode) { if(!(node = $(node))) return false; if(!(referenceNode = $(referenceNode))) return false; return referenceNode.parentNode.insertBefore(node, referenceNode.nextSibling); }; window['ADS']['insertAfter'] = insertAfter;
对于替换和删除一个节点的操作,可以使用replaceChild(newChild, oldChild)和removeChild(oldChild)方法来实现。例如,通过下面的代码将sample.html中的Firefox列表项替换成一个新节点:
ADS.addEvent(window, 'load', function() { ADS.log.header('Replace a node'); var newChild = document.createElement('LI') newChild.appendChild(document.createTextNode('A new list item!')); var firefoxLi = document.getElementById('firefoxListItem'); firefoxLi.parentNode.replaceChild(newChild,firefoxLi); });
而要删除Firefox列表项,只需要在相应节点的父节点上调用removeChild()方法即可:
ADS.addEvent(window, 'load', function() { ADS.log.header('Remove a node'); var firefoxLi = document.getElementById('firefoxListItem'); firefoxLi.parentNode.removeChild(firefoxLi); });
DOM新手常犯的一个错误是没有理解document.getElementById()方法返回的是对Node对象的引用,而不是相应对象的副本。如果运行下面的代码会有几个Firefox列表项呢?
ADS.addEvent(window, 'load', function() { ADS.log.header('Clone and Move a Node'); var firefoxLi = document.getElementById('firefoxListItem'); var firefoxLiClone = firefoxLi.cloneNode(true); var unorderedList = firefoxLi.parentNode; // 添加到列表中 unorderedList.appendChild(firefoxLi); // 添加到列表中 unorderedList.appendChild(firefoxLiClone); });
正确的答案是2个,即在列表底部有两个Firefox条目,位于上面的Firefox条目则消失了。这是因为通过document.getElementById()方法取得并把节点赋值给firefoxLi变量后,实际上取得是一个指向该节点的引用,而非节点的副本:
var firefoxLi = document.getElementById('firefoxListItem');
随后,当把这个引用添加到列表中时,appendChild()方法会取得引用的节点并将它添加到无序列表的末尾:
unorderedList.appendChild(firefoxLi);
也就是说,添加的是已经在文档中存在的一个节点的引用,所以节点被移动到了新位置。