七(3) . 最常见的JavaScript DOM方法实战-修改文档树 »
JavaScript DOM 修改文档树
在我们工作中大多数DOM脚本的主要任务就是在DOM文档中插入,删除和移动节点。W3C DOM 提供了4种方法来修改文档树。常用的是appendChild()和insertBefore(),而removeChild() 和replaceChild()很少用到。
在我们学习之前,我还是把总结好的DOM知识体系表放在前面以方便我们查阅。
Node接口定义的节点类型都包含的特性和方法
特性和方法后面的 “冒号:” 紧跟的单词是“返回值类型”
- 遍历节点(短途旅行):
- parentNode : Node
- firstChild : Node
- lastChild : Node
- nextSibling : Node
- previousSibling : Node
- childNodes : NodeList
- 节点信息:
- nodeName :String
- nodeType :number
- nodeValue :String
- 返回一个节点的根元素(文档对象):
- ownerDocument : Document
- 包含了代表一个元素的特性的Attr对象;仅用于Element节点:
- attributes : NamedNodeMap
- 获取对象层次中的父对象:
- parentElement [IE] :Node
- 修改文档树:
- appendChild(Node newChild) : Node
- insertBefore(Node newChild, Node refChild) : Node
- removeChild(Node oldChild): Node
- replaceChild(Node newChild, Node refChild) : Node
- 克隆一个节点:
- cloneNode(boolean deep) : Node
- 删除一个子节点:
- removeNode(boolean removeChildren) : Node
- 判断childNodes包含是否包含节点:
- hasChildNodes() : boolean
- Document
-
属性
- 自己的:
- documentElement : Element
- 继承 Node :
- attributes, childNodes, firstChild, lastChild, nextSibling, nodeName, nodeType, nodeValue, ownerDocument, parentElement, parentNode, previousSibling
-
方法
- 自己的:
-
- 创建元素:
- createElement(String tagName) : Element
- createTextNode(String data) : Text
- 查找元素:
- getElementById(String elementId) : Element
- getElementsByTagName(String tagname) : NodeList
- 继承 Node :
- appendChild, cloneNode, hasChildNodes, insertBefore, removeChild, removeNode, replaceChild
- Element
-
属性
- 自己的:
- tagName: String
- 继承 Node :
- attributes, childNodes, firstChild, lastChild, nextSibling, nodeName, nodeType, nodeValue, ownerDocument, parentElement, parentNode, previousSibling
-
方法
- 自己的:
-
- 属性的读写:
- getAttribute(String name) : String
- setAttribute(String name, String value) : void
-
- 其它:
- getElementsByTagName(String name) Stub : NodeList
- normalize() Stub : void
- removeAttribute(String name) : void
- 继承 Node :
- appendChild, cloneNode, hasChildNodes, insertBefore, removeChild, removeNode, replaceChild
一般用法
修改文档提供的4个方法,都是指向它们所作用的节点的引用。
下面我还是以我的导航条 HTML页面作为范例来解释这4个方法的应用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <div id="menu"> <h1>我的导航条</h1> <ul id="nav"> <li><a href="#">HOME</a></li> <li><a href="#">(X)Html / Css</a></li> <li><a href="#">Ajax / RIA</a></li> <li><a href="#">GoF</a></li> <li><a href="#">JavaScript</a></li> <li><a href="#">JavaWeb</a></li> <li><a href="#">jQuery</a></li> <li><a href="#">MooTools</a></li> <li><a href="#">Python</a></li> <li><a href="#">Resources</a></li> </ul> </div> |
appendChild()
appendChild()方法让你添加一个节点并使其成为某个元素的最后一个子节点。
如果添加的该节点已经存在于文档中,它会从当前位置移除。该节点的子节点保持不变,它们也被一起移动到新的位置。
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 | <script type="text/javascript"> window.onload=function(){ /*为一个元素添加子元素*/ var nav=document.getElementById("nav"); //创建一个li新元素 var newChild=document.createElement('li'); //创建一个a 新元素 var newLink=document.createElement('a') //创建一个 Text 节点 var newText=document.createTextNode('My Wiki'); //把Text添加到a元素节点中 newLink.appendChild(newText); //给a元素节点设置属性href和内容 newLink.setAttribute('href',"#"); //把a元素节点添加到新的li元素节点中 newChild.appendChild(newLink); //把新的li元素节点添加到 ul 元素节点里 nav.appendChild(newChild); /*<li>从原始位置上被移除,成为ul的最后一个子节点。它的a 元素节点和文本节点HODE也被移了过来*/ nav_list=nav.getElementsByTagName("li");//返回相同的一组元素 nav.appendChild(nav_list[0]); } </script> |
创建新DOM元素的通用函数
1 2 3 4 5 6 7 8 | <script type="text/javascript"> function create( elem ) { return document.createElementNS ? document.createElementNS( 'http://www.w3.org/1999/xhtml', elem ) : document.createElement( elem ); } </script> |
我们看到结果:
添加好的子节点

从原始位置上被移除,成为ul的最后一个子节点

insertBefore()
insertBefore()方法允许你在其他节点的前面插入一个节点,所以当你想要添加一个子节点,但又不希望该节点成为最后一个子节点的时候,就可以使用此方法。
就像appendChild()方法一样,如果插入的节点已经存在于文档之中,它会被从当前位置移除,而且该节点在被插入之后乃保持它的子节点结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <script type="text/javascript"> window.onload=function(){ var nav=document.getElementById("nav"); nav_list=nav.getElementsByTagName("li");//返回相同的一组元素 //第一个节点 var x=nav_list[0]; //最后一个节点 var y=nav_list[nav_list.length-1] //在x元素对象之前插入y元素对象 nav.insertBefore(y,x); //在x元素对象之前插入新生产的newChild元素对象 nav.insertBefore(newChild,x);//newChild元素对象的创建请参考上面的代码 } </script> |
在其他节点的前面插入一个节点

replaceChild()
replaceChild()方法允许你把一个节点替换为另一个节点。
就像appendChild()和insertBefore()一样,如果插入的节点已经存在于文档之中,它会被从当前位置移除,而且该节点在被插入之后乃保持它的子节点结构。
1 2 3 4 5 6 7 8 9 10 | <script type="text/javascript"> window.onload=function(){ var nav=document.getElementById("nav"); nav_list=nav.getElementsByTagName("li");//返回相同的一组元素 //第一个节点对象 var x=nav_list[0]; //x节点对象被newChild新节点对象替换了 nav.replaceChild(newChild,x); } </script> |
把一个节点替换为另一个节点

removeChild()
removeChild()方法允许你移除一个节点以及它的子节点们。
1 2 3 4 5 6 7 8 9 10 | <script type="text/javascript"> window.onload=function(){ var nav=document.getElementById("nav"); nav_list=nav.getElementsByTagName("li");//返回相同的一组元素 //最后一个节点 var y=nav_list[nav_list.length-1] //移除最后面的一个节点 nav.removeChild(y); } </script> |
你移除一个节点以及它的子节点们

移除所有的子节点
有的时候你需要把一个元素清除干净;你想在添加新节点前清除原来的所有子点。
有两个简单的方法来做这件事情:
1 2 3 4 5 6 7 8 9 10 11 12 | <script type="text/javascript"> while (x.childNodes[0]){ x.removeChild(x.childNodes[0]); } /* //我们可以使用firstChild来代替childNodes[0] while (x.firstChild){ x.removeChild(x.firstChild); } * / </script> |
这是一个简单的while()循环,只要元素存在第一个节点(childNodes[0]),它就移除这个节点,接着节点集合立即更新。所以(原来的)第二个节点成为了第一个节点,循环就会一直重复,直到X没有子节点为止。
另一个方法就简单了
1 2 3 | <script type="text/javascript"> x.innerHTML=''; </script> |
辅助函数
appendChild()和insertBefore()都有2个参数,但是我们在应用的时候,还要注意参数的先后顺序。
既然这么麻烦我们还是自己写一些辅助函数来代替原有的appendChild()和insertBefore()。
在另一个元素之前插入元素的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <script type="text/javascript"> //insertBefore()的代替方法 function before( parent, before, elem ) { // Check to see if no parent node was provided //检查parent是否传入 if ( elem == null ) { elem = before; before = parent; parent = before.parentNode; } // Get the new array of elements //获取元素的新数组 var elems = checkElem( elem ); // Move through the array backwards, // because we’re prepending elements //向后遍历数组 //因为我们向前插入元素 for ( var i = elems.length - 1; i >= 0; i-- ) { parent.insertBefore( elems[i], before ); } } </script> |
为另一个元素添加一个子元素:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <script type="text/javascript"> //appendChild()的代替方法 function append( parent, elem ) { // Get the array of elements //获取元素数组 var elems = checkElem( elem ); // Append them all to the element //把它们所有都追加到元素中 for ( var i = 0; i <= elems.length; i++ ) { parent.appendChild( elems[i] ); } } </script> |
before和append的辅助函数:
1 2 3 4 5 6 7 8 | <script type="text/javascript"> function checkElem( elem ) { // If only a string was provided, convert it into a Text Node //如果只提供字符串,那就把它转换为文本节点 return elem && elem.constructor == String ? document.createTextNode( elem ) : elem; } </script> |
注意:constructor的用法。
有时你可能需要对变量进行类型检查,或者判断变量是否已定义。有两种方法可以使用:typeof函数与constructor属性。
typeof可以检查到变量是否有定义,而construct只能检查已定义变量的类型。
移除所有的子节点的辅助函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <script type="text/javascript"> function empty( elem ) { while (elem.firstChild){ remove(elem.firstChild); } /* //我们可以使用firstChild来代替childNodes[0] while (elem.childNodes[0]) remove(elem.childNodes[0]); * / } function remove( elem ) { if ( elem ) elem.parentNode.removeChild( elem ); } </script> |
下一节中我们开始讨论 W3C DOM 的创建和克隆元素的方法。