【JavaScript】DOM节点树操作总结

前言:打开一个页面,浏览器首先做的就是绘制节点树,也就是说,我们删除标签元素,添加标签元素,其实就是在删除节点,添加节点,也就是说在DOM节点数上进行操作。

一、节点树


(画工技术一般般,哈哈..儿童节快乐)

这是一个很简单的节点树,<!DOCTYPE html>相当于这棵节点说的根,也称为文档节点,文档节点有且只有一个。文档节点下也只有一个子节点,那就是<html>标签,我喜欢把它比作这棵节点树的主干,而<head>,<body>标签是<html>标签的子节点,就是主干上的两条分支。在<head>,<body>下又有更多的子节点,更多分支。

二、获取子节点(childNodes)

可以通过childNodes获取到该节点下的所有子节点类数组(NodeList类数组),NodeList类数组与我们以前见到的arguments类数组不同的是,Nodelist类数组有length属性。

<body>
    <ul id="myList">
        hello ChildNodes
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <script>
        var element = document.getElementById('myList');
        alert(element.childNodes.length);
    </script>
<body>

猜一下输出结果吧。我相信没有接触过的朋友可能会说有3个li标签,那就是有3个子节点。或者是说4个节点,文字也算一个节点。

但是输出结果其实是7.


但是在iE8及IE8以下浏览器输出的是4


总结:其实在li标签之间还存在空白符,而空白符也被算是一个节点。我们试着不换行就行了。(文本节点前后不会产生空白符,因为空白符也是文本节点)

<body>
    <ul id="myList">
    	hello ChildNodes
        <li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>
    <script>
        var element = document.getElementById('myList');
        alert(element.childNodes.length);
    </script>
<body>

这时候不存在空白符就输出了4了


三、子节点的名字(nodeName)

<body>
    <ul id="myList">
    	hello ChildNodes
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <script>
		var element = document.getElementById('myList');
		for(var i =0,len=element.childNodes.length; i<len; i++){
			console.log(element.childNodes[i].nodeName);
		}
    </script>
<body>

输出结果


从输出结果终于可以看出那"神奇"的空白符节点的庐山真面目了,空白符节点也归类于文本节点。


四、子节点的节点类型(nodeType)

像上面例子中,我们接触到了三个节点类型:元素节点,文本节点。而我们比较长用到的就是元素节点跟文本节点了。像上面的例子,如果我们要剔除文本节点带来的困扰,我们可以通过判断他的节点类型。

元素节点的nodeType值为1;

文本节点的nodeType值为3;

<body>
    <ul id="myList">
    	hello ChildNodes
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <script>
		var element = document.getElementById('myList');
        var length=0;
		for(var i =0,len=element.childNodes.length; i<len; i++){
			if(element.childNodes[i].nodeType ==1 ){
				length++;
			}
		}
		console.log(length);
    </script>
<body>

这时候就输出3了,有3个li标签,所以只有3个元素节点。


五、获取子节点的内容(nodeValue)

<div id="box">
	文本节点
    <p>普通元素节点</p>
    <input type="text" value="表单元素节点"/>
</div>
<script>
	var node = document.getElementById('box');
	console.log(node.childNodes[0].nodeValue);
	console.log(node.childNodes[1].innerText);
	console.log(node.childNodes[2].nodeValue);
	console.log(node.childNodes[3].value);
</script>
</body>

输出结果


这空白符节点的真是一片空白呀!


六、添加子节点

①、appendChild:在子节点的最后一位插入新节点

<body>
    <ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <script>
		var element = document.getElementById('myList');
		var newLi = document.createElement('li');    //创建新的节点
		newLi.innerText = 'new Item';
		element.appendChild(newLi);		//插入新创建的节点
    </script>
<body>

②insertBefore:在子节点的最后一位插入新节点

<body>
    <ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <script>
		var element = document.getElementById('myList');
		var newLi = document.createElement('li');    //创建新的节点
		newLi.innerText = 'new Item';
		element.insertBefore(newLi,null);	//插入新创建的节点
    </script>
<body>

③、insertBefore在第一个子节点前面插入新节点

<body>
    <ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <script>
		var element = document.getElementById('myList');
		var newLi = document.createElement('li');    //创建新的节点
		newLi.innerText = 'new Item';
		element.insertBefore(newLi,element.firstChild);	 //在第一个子节点前面插入新节点
    </script>
<body>

④、insertBefore在任意元素节点前面插入新节点

前面的例子已经展示过空白符文本节点带来的困扰,要排除空白符文本节点带来的困扰,我们需要进行其他处理下。

<body>
    <ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <script>
		var aNodeList = [];      //用于保存元素节点对象
		var element = document.getElementById('myList');
		var newLi = document.createElement('li');    //创建新的节点
		newLi.innerText = 'new Item';
		for(var i =0,len=element.childNodes.length; i<len; i++){
			if(element.childNodes[i].nodeType ==1 ){
				aNodeList.push(element.childNodes[i]);
			}
		}
		
		element.insertBefore(newLi,aNodeList[1]);	 //在第任意元素子节点前面插入新节点
    </script>
<body>

这样我们只需要输入对应的元素子节点的索引,就可以往其前面插入子节点了。

⑤、insertBefore多次插入同一个新节点时出现的问题

<body>
    <ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <script>
		var aNodeList = [];      //用于保存元素节点对象
		var element = document.getElementById('myList');
		var newLi = document.createElement('li');    //创建新的节点
		newLi.innerText = 'new Item';
		for(var i =0,len=element.childNodes.length; i<len; i++){
			if(element.childNodes[i].nodeType ==1 ){
				aNodeList.push(element.childNodes[i]);
			}
		}
		element.insertBefore(newLi,aNodeList[0]);	 //在第一位元素子节点前面插入新节点
		element.insertBefore(newLi,aNodeList[1]);	 //在第二位元素子节点前面插入新节点
		element.insertBefore(newLi,aNodeList[2]);	 //在第二位元素子节点前面插入新节点
    </script>
<body>

运行代码:


发现并没有想象中的添加三个new Item,而只是添加一个而已。只是因为我们第一次添加新节点后,new Item已经是文档节点的一部分了,如果我们进行第二次添加,那结果就是将该新节点从原来的位置转移到新位置。任何DOM节点不能同时出现在文档中的多个位置上。

七、解决以上问题(克隆节点cloneNode)

<body>  
    <ul id="myList">  
        <li>Item 1</li>  
        <li>Item 2</li>  
        <li>Item 3</li>  
    </ul>  
    <script>  
        var aNodeList = [];      //用于保存元素节点对象  
        var element = document.getElementById('myList');  
        var newLi = document.createElement('li');    //创建新的节点  
        newLi.innerText = 'new Item';  
		newLi.style.color = 'red';
        for(var i =0,len=element.childNodes.length; i<len; i++){  
            if(element.childNodes[i].nodeType ==1 ){  
                aNodeList.push(element.childNodes[i]);  
            }  
        }  
        element.insertBefore(newLi,aNodeList[0]);   //在第一位元素子节点前面插入新节点
		
		var newLi1 = newLi.cloneNode();  			//克隆newLi节点(没添加true)
        element.insertBefore(newLi1,aNodeList[1]);  //在第二位元素子节点前面插入新节点
		  
		var newLi2 = newLi.cloneNode(true);			//克隆newLi节点
        element.insertBefore(newLi2,aNodeList[2]);  //在第二位元素子节点前面插入新节点  
    </script>  
<body>  

运行代码:


这时就很好的解决一个节点无法多次添加问题。cloneNode() 方法能克隆节点所有属性,(如果类名,属性),但是想要克隆节点的后代,如上面newLi里面的文字节点。


八、替换子节点(replaceChild)

<body>
    <ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <script>
		var aNodeList = [];      //用于保存元素节点对象
		var element = document.getElementById('myList');
		var newLi = document.createElement('li');    //创建新的节点
		newLi.innerText = 'new Item';
		for(var i =0,len=element.childNodes.length; i<len; i++){
			if(element.childNodes[i].nodeType ==1 ){
				aNodeList.push(element.childNodes[i]);
			}
		}
		element.replaceChild(newLi,aNodeList[0]);  //替换第一个元素子节点
		element.replaceChild(newLi,aNodeList[1]);  //替换第二个元素子节点
		element.replaceChild(newLi,aNodeList[aNodeList.length-1]);  //替换最后一个元素子节点
    </script>
<body>
运行代码会发现,并不是出现三个"new Item",而是只有一个"new Item"。这是因为当替换一个节点时,该节点的所有关系指针都会被从被它替换的节点复制过来。就是说我们替换第二个元素子节点的时候,newLi已经是第一个元素子节点了,相当于我们先移除第二个元素子节点,然后把已经变成第一个元素子节点的newLi移到第二个元素子节点的位置上。

九、检测是否有改子节点(hasChildNodes)

<body>
    <ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <script>
		var element = document.getElementById('myList');
		var newLi = document.createElement('li');    //创建新的节点
		newLi.innerText = 'new Item';
		element.appendChild(newLi);		//插入新创建的节点
		console.log(element.hasChildNodes(newLi));   //检测是否有newLi节点
    </script>
<body> 

有就返回true,没有就返回false。


十、移除子节点

<body>
    <ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <script>
		var aNodeList = [];      //用于保存元素节点对象
		var element = document.getElementById('myList');
		for(var i =0,len=element.childNodes.length; i<len; i++){
			if(element.childNodes[i].nodeType ==1 ){
				aNodeList.push(element.childNodes[i]);
			}
		}
		element.removeChild(aNodeList[0]);	//移除第一个元素子节点
		element.removeChild(aNodeList[1]);	//移除第二个元素子节点
		element.removeChild(aNodeList[aNodeList.length-1]); //移除最后一个元素子节点
    </script>
<body>
被移除的节点仍然未文档节点中(既是上面说的节点树的根中),只不过在文档节点中已经没有了它的位置了。

猜你喜欢

转载自blog.csdn.net/w390058785/article/details/80534328