本文详细对比了原生JavaScript与jQuery在获取父级、子级及兄弟元素时的实现差异。重点解析了Firefox浏览器将换行符视为文本节点导致的childNodes长度异常问题,并提供通过遍历删除空白文本节点的兼容方案。同时梳理了jQuery中parent、children、siblings等核心API的用法及find与filter的区别,帮助开发者在不同场景下选择最优方案。
JavaScript与jQuery获取DOM节点:父子兄弟元素查找与跨浏览器兼容处理
首先介绍原生JavaScript的获取方式,其实现复杂度通常高于jQuery,下文将以此为基础进行对比说明。
原生JS方法相对繁琐,主要难点在于Firefox等浏览器会将HTML中的换行符也解析为DOM元素,从而干扰元素计数。
以获取ID为test的元素下的子元素为例,原生JS需通过特定属性或方法实现。
具体示例如下所示。
<div id="dom"> <div></div> <div></div> <div></div> </div>
使用以下代码可以正常获取元素:var a = document.getElementById("dom").getElementsByTagName("div"); 这种方式在多数情况下没有问题。
此时,变量a的长度a.length等于3。
然而,若采用另一种方式获取子节点,例如前文提到的var b = document.getElementById("dom").childNodes; 在IE浏览器中alert(b.length)显示为3,但在Firefox浏览器中会显示为4。这是因为Firefox将代码中的换行符也识别为一个文本节点。因此,必须对结果进行处理才能正确使用JS的相关属性。处理思路是遍历子节点,删除类型为空格且内容为文本的节点。处理函数如下所示。
代码如下:
function del_space(elem){
var elem_child = elem.childNodes; // 获取参数元素的所有子元素
for(var i=0;i<elem_child.length;i++){ // 遍历子元素
if(elem_child.nodeName == "#text" && !/\S/.test(elem_child.nodeValue)) {
elem.removeChild(elem_child)}
}
}上述函数遍历子元素,当检测到节点类型为文本且节点值为空(即仅包含空白字符)时,将其从父元素中移除。
nodeName属性用于获取节点的类型,/\S/是JS中正则表达式,表示非空字符。前面加上感叹号!表示匹配空字符(即纯空白)。
test()方法用于检测字符串是否匹配某个模式,其语法为:RegExpObject.test(string)。
如果字符串string中包含与RegExpObject匹配的文本,则返回true,否则返回false。
nodeValue属性用于获取节点的值。
removeChild方法用于删除元素的子节点。
接下来是核心代码示例。
代码如下:
<div id = "dom">
<div></div>
<div></div>
<div></div>
</div>
<script>
function dom(){
var a = document.getElementById("dom");
del_space(a); // 调用清理空格的函数
var b = a.childNodes; // 获取a的全部子节点;
var c = a.parentNode; // 获取a的父节点;
var d = a.nextSibling; // 获取a的下一个兄弟节点
var e = a.previousSibling; // 获取a的上一个兄弟节点
var f = a.firstChild; // 获取a的第一个子节点
var g = a.lastChild; // 获取a的最后一个子节点
}
</script>下面介绍jQuery中关于父节点、子节点和兄弟节点的查找方法。
jQuery.parent(expr)用于查找父亲节点,可传入表达式进行过滤,例如$("span").parent()或$("span").parent(".class")。
jQuery.parents(expr)类似于parent(),但会查找所有祖先元素,而不限于直接父元素。
jQuery.children(expr)返回所有直接子节点,该方法仅返回直接的孩子节点,不包含所有的子孙节点。
jQuery.contents()返回内部的所有内容,包括节点和文本。
与children()的区别在于,contents()会将空白文本也作为一个节点返回,而children()仅返回节点。
jQuery.prev()返回上一个兄弟节点,并非所有之前的兄弟节点。
jQuery.prevAll()返回所有之前的兄弟节点。
jQuery.next()返回下一个兄弟节点,并非所有之后的兄弟节点。
jQuery.nextAll()返回所有之后的兄弟节点。
jQuery.siblings()返回所有兄弟节点,不分前后顺序。
jQuery.find(expr)与jQuery.filter(expr)功能完全不同。jQuery.filter()是从初始的jQuery对象集合中筛选出一部分,而jQuery.find()的返回结果不包含初始集合中的内容。
例如$("p").find("span"),是从p元素开始查找,等同于$("p span")。
具体用法见上述示例。
——————————————2014 1-9————————————————
以上是从网络整理的解决JS和jQuery获取父子元素等方法,但在实际解决过程中仍可能遇到问题。
代码如下:
<script type="text/javascript">
//JS解决方案
var dom=document.getElementById("dom");
//为避免Firefox出现的问题,对子元素进行过滤处理
del_space(dom);
//1.获取dom下的所有子节点
var a = dom.childNodes; // 全部子节点;
var b = dom.parentNode; // 父节点;
var e = dom.firstChild; // 第一个子节点
var f = dom.lastChild; // 最后一个子节点
//由于未知原因,待后续研究,获取下一个兄弟节点和上一个兄弟节点均无法成功...--!
var c = dom.nextSibling.nodeType; // 下一个兄弟节点
var d = dom.previousSibling; // 上一个兄弟节点
//jQuery解决方案
var a1 = $("#dom").children(); // 全部子节点;
var b2 = $("#dom").parent(); // 父节点;
var c3 = $("#dom").next(); // 下一个兄弟节点
var d4 = $("#dom").prev(); // 上一个兄弟节点
var e5 = $("#dom").children(":first"); // 第一个子节点
var f6 = $("#dom").children(":last"); // 最后一个子节点
/*
alert(a.length);
for(var i=0;i<a.length;i++){
alert(a[i].nodeName+":"+a[i].nodeValue+":"+/\s/.test(a[i].nodeValue));
}
*/
//在Firefox下会默认将换行当作dom元素,因此必须进行过滤处理,IE下不会产生类似问题
function del_space(elem){
var elem_child = elem.childNodes; // 得到参数元素的所有子元素
for ( var i = 0; i < elem_child.length; i++) { // 遍历子元素
if (elem_child[i].nodeName == "#text") {
elem.removeChild(elem_child[i]);
}
}
}
</script>js获取节点 dom操作
|
接口 |
nodeType常量 |
nodeType值 |
备注 |
|
Element |
Node.ELEMENT_NODE |
1 |
元素节点 |
|
Text |
Node.TEXT_NODE |
3 |
文本节点 |
|
Document |
Node.DOCUMENT_NODE |
9 |
document |
|
Comment |
Node.COMMENT_NODE |
8 |
注释的文本 |
|
DocumentFragment |
Node.DOCUMENT_FRAGMENT_NODE |
11 |
document片断 |
|
Attr |
Node.ATTRIBUTE_NODE |
2 |
节点属性 |
|
方法 |
描述 |
|
createAttribute() |
用指定的名字创建新的Attr节点。 |
|
createComment() |
用指定的字符串创建新的Comment节点。 |
|
createElement() |
用指定的标记名创建新的Element节点。 |
|
createTextNode() |
用指定的文本创建新的TextNode节点。 |
|
getElementById() |
返回文档中具有指定id属性的Element节点。 |
|
getElementsByTagName() |
返回文档中具有指定标记名的所有Element节点。 |
|
属性 |
描述 |
|
attributes |
如果该节点是一个Element,则以NamedNodeMap形式返回该元素的属性。 |
|
childNodes |
以Node[]的形式存放当前节点的子节点。如果没有子节点,则返回空数组。 |
|
firstChild |
以Node的形式返回当前节点的第一个子节点。如果没有子节点,则为null。 |
|
lastChild |
以Node的形式返回当前节点的最后一个子节点。如果没有子节点,则为null。 |
|
nextSibling |
以Node的形式返回当前节点的兄弟下一个节点。如果没有这样的节点,则返回null。下一个兄弟节点 |
|
nodeName |
节点的名字,Element节点则代表Element的标记名称。 |
|
nodeType |
代表节点的类型。 |
|
parentNode |
以Node的形式返回当前节点的父节点。如果没有父节点,则为null。 |
|
previousSibling |
以Node的形式返回紧挨当前节点、位于它之前的兄弟节点。如果没有这样的节点,则返回null。上一个兄弟节点 |