今天在帮人解决DOM节点问题时,把遇到的childNodes的空格问题在这总结下。
问题大概是这样的:把下面左边的四个节点一次性全部移到右边或把右边的节点一次性移到左边(>>右移,<<左移),
开始的实现是这样的:
<html> <head> <title>MyHtml.html</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!--<link rel="stylesheet" type="text/css" href="./styles.css">--> <script type="text/javascript"> function allToRigth(){ var nodes = document.getElementById("leftSelect").childNodes;//得到leftSelect的所有孩子节点 for(var i = 0; i < nodes.length; i ++){ //遍历所有孩子节点 if(nodes [i].nodeType == 1){ document.getElementById("rightSelect").appendChild(nodes[i]); //当孩子节点是元素节点时就右移 } } } function allToLeft(){ var nodes= document.getElementById("rightSelect").childNodes;//得到rightSelect的所有孩子节点 for(var i = 0; i < nodes.length; i ++){//遍历所有孩子节点 if(nodes[i].nodeType == 1){ document.getElementById("leftSelect").appendChild(nodes[i]); //当孩子节点是元素节点时就左移 } } } </script> </head> <body> <table width="200"> <td> <select size="4" id="leftSelect"> <option>hadoop</option> <option>hbase</option> <option>hive</option> <option>pig</option> </select> </td> <td> <input type="button" value=">>" id="allToRigth" onclick="allToRigth()"><br> <input type="button" value="<<" id="allToLeft" onclick="allToLeft()"> </td> <td> <select size="4" id="rightSelect"> </select> </td> </table> </body> </html>
结果:
右移:
再左移:(问题出现了:在再进行左移时并不能一次性把节点都移到左边)。
这里我我先分析下用 元素.childNodes 得到的节点的空格问题(测试所用浏览器及版本号:chrom 64位,IE11,火狐39.0,Edge);
现在的大部分浏览器在解析childNodes时都会把"#text"(空格,制表符,换行符等一些表示空白文本的符号)当成一个节点,但低版本的IE不会。
所以document.getElementById("leftSelect").childNodes得到的节点个数为9;
(左列表:两块黄色的部分表示一个节点,<option></option>表示一个节点,有9个节点)
(右列表:两块黄色的部分表示一个节点,有1个节点)
下面是用FireBug调试的过程:
1.开始状态:
注意红色框部分,节点分别是TextNode,option,TextNode,option,TextNode,option,TextNode,option,TextNode.这9个节点(TextNode是空白文本)
2.第一个option节点移到右边后:
注意:在第一个option节点移走后,option后面的节点TextNode补了上来, 但在这次右移过程中这并不影响我们。
在全部节点移到右边后,我们来看左移这部分;
3.开始状态:有5个节点,一个TextNode节点,四个option节点。
4,第一个option节点移到左边后:
看吧,在第一个option节点移到左边后,i=2,后面的option节点补了上来,但补的位置又是已经访问过的位置(i=1)了,这样就造成了节点"遗漏"了,最后变成这样
。
这就是问题的根本原因了。
这里给出其中一个解决方案。
思路:在取孩子节点时我们从最后一个孩子节点开始取,这样即使移走一个孩子节点后,后面的节点补上来也不影响前面孩子节点的位置。
代码实现:
<html> <head> <title>example2.html</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!--<link rel="stylesheet" type="text/css" href="./styles.css">--> <script type="text/javascript"> function allToRigth(){ var nodes = document.getElementById("leftSelect").childNodes;//得到leftSelect的所有孩子节点 for(var i = nodes .length-1; i >=0 ; i --){ //倒着遍历所有孩子节点 if(nodes [i].nodeType == 1){ //当孩子节点是元素节点时就插入到rightSelect的第一个孩子节点之前 document.getElementById("rightSelect").insertBefore(nodes [i],document.getElementById("rightSelect").firstChild); } } } function allToLeft(){ var nodes = document.getElementById("rightSelect").childNodes;//得到rightSelect的所有孩子节点 for(var i = nodes .length-1; i >=0 ; i --){ //倒着遍历所有孩子节点 if(nodes [i].nodeType == 1){ //当孩子节点是元素节点时就插入到leftSelect的第一个孩子节点之前 document.getElementById("leftSelect").insertBefore(nodes [i],document.getElementById("leftSelect").firstChild); } } } </script> </head> <body> <table width="200"> <td> <select size="4" id="leftSelect"> <option>hadoop</option> <option>hbase</option> <option>hive</option> <option>pig</option> </select> </td> <td> <input type="button" value=">>" id="allToRigth" onclick="allToRigth()"><br> <input type="button" value="<<" id="allToLeft" onclick="allToLeft()"> </td> <td> <select size="4" id="rightSelect"> </select> </td> </table> </body> </html>
这样,无论我们怎样移动都能正常的全部移到一边。