JavaScript进行DOM操作时的一点点小经验
今天打算写一个函数,根据给定的DOM对象或者id值,找到其所有后代节点(包括子节点的子节点)中的input type=="text"的元素,代码如下:
1 /** 2 * [clearUserInput 根据元素的ID找到其子节点(包括子节点的子节点)中的input元素并且type="text",将其value设为空] 3 * @param {[type]} id [DOM对象或者字符串表示元素的id值] 4 * @return {[type]} [description] 5 */ 6 function clearUserInput(id){ 7 //参数校验 8 if(id === undefined){consoloe.log("参数必须");return 1;}//判断参数是否存在 9 id = ((typeof id) === "object")?id:document.getElementById(id);//获取对象 10 if(id === null){consoloe.log("未知对象"); return 2;}//typeof null === "object" 11 12 var childrens = id.childNodes,len=childrens.length; i=0; 13 for(i;i<len;i++){ 14 if(childrens[i] === undefined){return;}//到达边界 15 if(childrens[i].nodeType === 3){continue;} 16 if(childrens[i].childNodes.length !== 0){ 17 arguments.callee(childrens[i]); 18 } 19 if(childrens[i].nodeName === "INPUT" && childrens[i].type === "text"){ 20 childrens[i].value = ""; 21 } 22 } 23 }
可是写的时候,我对nodeName和type这两个属性的返回值有点不放心,不知道在不同的浏览器下面他们分别怎样显示。如果很强制的把属性值都通过toUpperCase()转换成大写的然后再比较,也可以,但总觉得有点心有不甘。所以专门写了个测试的页面,看看他们在各个浏览器中的效果
测试页面代码如下:
1 <!DOCTYPE HTML> 2 <html lang="en-US"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>test</title> 6 7 </head> 8 <body> 9 <div id="par"> 10 <div id="a">a</div> 11 <p id="b">bb</p> 12 cc 13 <div id="c">ccc</div> 14 <input id="d" type="text" /> 15 </div> 16 <script type="text/javascript"> 17 var par = document.getElementById("par"); 18 var str = ""; 19 str +="child num: "+par.childNodes.length+"\n"; 20 for(var i=0;i<par.childNodes.length;i++){ 21 str +="childNodes " + i + ":\n"+ 22 " nodeType: "+par.childNodes[i].nodeType+"\n"+ 23 " nodeName: "+par.childNodes[i].nodeName+"\n"; 24 if(par.childNodes[i].nodeName === "INPUT"){ 25 str += " type: "+par.childNodes[i].type+"\n"; 26 } 27 } 28 alert(str); 29 </script> 30 </body> 31 </html>
下面是几个浏览器的效果截图:
Chrome Firefox Opera
Safari IE8
IE7 IE6
以上测试中,仅IE7是通过IETester进行的,结果的准确性没法保证
从以上测试中,我们可以得出以下几个结论:
- 对于nodeType和nodeName,还有input type=="text"的type属性,各个浏览器的支持很一直,大家可以放心使用,注意nodeName的结果都是大写的
- 各个浏览器对元素的子节点的定义有点不同,可以看到在上面例子中,Chrome,Firefox,Opera和Safari都判定有9个节点而IE6,7,8都认为是有6个节点。可以看出两方判定的不同之处在于对文本节点的判断。在Chrome,Firefox,Opera和Safari中,似乎每一个非文本节点的节点前面都有一个文本节点,而IE中则没有这样的现象。针对这点,所以在遍历DOM的时候最好不要针对性的用类似obj.childNodes[2]这样的方法去指定某个节点,因为在不同浏览器中它们的位置可能不一样。最好的方法是判断id,属性等等
后来我怀疑是不是因为文档中的回车键的原因所以我使用window.console.log(par.childNodes),然后在Chrome的控制台里面看看各个文本节点里面的内容都分别是什么
果然,都是回车键,于是我把测试代码中的缩进全部去除
<div id="par"> <div id="a">a</div> <p id="b">bb</p> cc <div id="c">ccc</div> <input id="d" type="text" /> </div>
在Chrome,Firefox,Opera,Safari里面节点数量还是9
接着我在按下面的方式排列html
<div id="par"><div id="a">a</div><p id="b">bb</p>cc<div id="c">ccc</div><input id="d" type="text" /></div>
在Chrome,Firefox,Opera和Safari里面效果都如上所示,只有我们真正需要的文本节点出现
再看IE
在IE6,7,8中的结果也和上面统一了
可见,在Chrome,Firefox,Opera,Safari中,是会把每个标签后面的回车键当成文本节点的,而IE中似乎是只有最后一个子节点和父节点标签之间回车键会被当成文本节点。为了证实这一点,我再次改变了测试代码的排版
排版1:
<div id="par"><div id="a">a</div><p id="b">bb</p>cc<div id="c">ccc</div><input id="d" type="text" /> </div>
排版2:
<div id="par"><div id="a">a</div><p id="b">bb</p>cc<div id="c">ccc</div> <input id="d" type="text" /> </div>
两次排版之后的结果都是子节点数量为6,而且最后一个是文本节点,与开始时候一样。我想,这应该能够说明IE中,子节点之间的回车键会被忽略,而最后一个子节点与父节点结束标签之间的回车键会被当成文本节点了。
最后做一次总结:
- 在Chrome,Firefox,Opear,Safari中,子节点之间,最后一个子节点与父节点结束标签之间的回车键都会被当成文本节点
- 在IE中子节点之间的回车键会被忽略,而最后一个子节点与父节点结束标签之间的回车键会被当成文本节点
- 节点之间的Tab缩进都会被忽略
- 为了防止子节点定位错误,不要明显的使用一个数字去定位某个子节点,用这样的错误方式:obj.childNodes[2]
- 鉴于回车键会被当成文本节点,所以HTML文档的压缩很有必要,这样会使得整个DOM树的大小减少很多,对文档的解析和我们用javascript遍历DOM都能带来很大的便利