如何使用jQueryselect文本节点?

我想获得一个元素的所有后代文本节点,作为一个jQuery集合。 什么是最好的方法来做到这一点?

jQuery没有一个方便的function。 你需要结合contents() ,这将只给子节点,但包括文本节点, find() ,它给所有的后代元素,但没有文字节点。 以下是我想到的:

 var getTextNodesIn = function(el) { return $(el).find(":not(iframe)").addBack().contents().filter(function() { return this.nodeType == 3; }); }; getTextNodesIn(el); 

注意:如果您使用jQuery 1.7或更早的版本,上面的代码将不起作用。 要解决这个问题,用addBack()replaceandSelf() addBack()从1.8开始,赞成使用addBack()

这与纯DOM方法相比效率不高,并且必须包含一个丑陋的解决方法,以便jQuery重载其contents()函数 (感谢@rabidsnail在注释中指出了这一点),所以这里是非jQuery解决scheme,使用一个简单的recursionfunction。 includeWhitespaceNodes参数控制输出中是否包含空白文本节点(在jQuery中它们被自动过滤掉)。

更新:修正了includeWhitespaceNodes错误时的错误。

 function getTextNodesIn(node, includeWhitespaceNodes) { var textNodes = [], nonWhitespaceMatcher = /\S/; function getTextNodes(node) { if (node.nodeType == 3) { if (includeWhitespaceNodes || nonWhitespaceMatcher.test(node.nodeValue)) { textNodes.push(node); } } else { for (var i = 0, len = node.childNodes.length; i < len; ++i) { getTextNodes(node.childNodes[i]); } } } getTextNodes(node); return textNodes; } getTextNodesIn(el); 

Jauco在评论中发表了一个很好的解决scheme,所以我在这里复制它:

 $(elem) .contents() .filter(function() { return this.nodeType === 3; //Node.TEXT_NODE }); 
 $('body').find('*').contents().filter(function () { return this.nodeType === 3; }); 

可以使用jQuery.contents()jQuery.filter来查找所有的子文本节点。 稍微转一下,你也可以find孙子的文字节点。 无需recursion:

 $(function() { var $textNodes = $("#test, #test *").contents().filter(function() { return this.nodeType === Node.TEXT_NODE; }); /* * for testing */ $textNodes.each(function() { console.log(this); }); }); 
 div { margin-left: 1em; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <div id="test"> child text 1<br> child text 2 <div> grandchild text 1 <div>grand-grandchild text 1</div> grandchild text 2 </div> child text 3<br> child text 4 </div> 

如果可以假设所有的孩子都是元素节点或文本节点,那么这是一个解决scheme。

要将所有子文本节点作为jquery集合:

 $('selector').clone().children().remove().end().contents(); 

要删除删除了非文本子项的原始元素的副本:

 $('selector').clone().children().remove().end(); 

也可以这样做:

 var textContents = $(document.getElementById("ElementId").childNodes).filter(function(){ return this.nodeType == 3; }); 

以上代码从给定元素的直接子节点中过滤textNode。

出于某种原因, contents()不适合我,所以如果它不适合你,这是我做的一个解决scheme,我创build了jQuery.fn.descendants与包含文本节点的选项

用法


获取所有的后代,包括文本节点和元素节点

 jQuery('body').descendants('all'); 

获取所有的后代只返回文本节点

 jQuery('body').descendants(true); 

获取所有后代只返回元素节点

 jQuery('body').descendants(); 

咖啡原文

 jQuery.fn.descendants = ( textNodes ) -> # if textNodes is 'all' then textNodes and elementNodes are allowed # if textNodes if true then only textNodes will be returned # if textNodes is not provided as an argument then only element nodes # will be returned allowedTypes = if textNodes is 'all' then [1,3] else if textNodes then [3] else [1] # nodes we find nodes = [] dig = (node) -> # loop through children for child in node.childNodes # push child to collection if has allowed type nodes.push(child) if child.nodeType in allowedTypes # dig through child if has children dig child if child.childNodes.length # loop and dig through nodes in the current # jQuery object dig node for node in this # wrap with jQuery return jQuery(nodes) 

放在Javascript版本中

 var __indexOf=[].indexOf||function(e){for(var t=0,n=this.length;t<n;t++){if(t in this&&this[t]===e)return t}return-1}; /* indexOf polyfill ends here*/ jQuery.fn.descendants=function(e){var t,n,r,i,s,o;t=e==="all"?[1,3]:e?[3]:[1];i=[];n=function(e){var r,s,o,u,a,f;u=e.childNodes;f=[];for(s=0,o=u.length;s<o;s++){r=u[s];if(a=r.nodeType,__indexOf.call(t,a)>=0){i.push(r)}if(r.childNodes.length){f.push(n(r))}else{f.push(void 0)}}return f};for(s=0,o=this.length;s<o;s++){r=this[s];n(r)}return jQuery(i)} 

Unminified的Javascript版本: http ://pastebin.com/cX3jMfuD

这是跨浏览器,代码中包含一个小的Array.indexOf

我得到了许多空的文本节点与接受的filterfunction。 如果您只想select包含非空格的文本节点,可以尝试为filter函数添加一个nodeValue条件,如简单的$.trim(this.nodevalue) !== ''

 $('element') .contents() .filter(function(){ return this.nodeType === 3 && $.trim(this.nodeValue) !== ''; }); 

http://jsfiddle.net/ptp6m97v/

或者为了避免内容看起来像空白而不是(例如,软连字符&shy;字符,换行符,标签等)的奇怪情况,您可以尝试使用正则expression式。 例如, \S将匹配任何非空白字符:

 $('element') .contents() .filter(function(){ return this.nodeType === 3 && /\S/.test(this.nodeValue); }); 

如果你想剥离所有的标签,然后试试这个

function:

 String.prototype.stripTags=function(){ var rtag=/<.*?[^>]>/g; return this.replace(rtag,''); } 

用法:

 var newText=$('selector').html().stripTags(); 

对我来说,简单的老.contents()似乎工作来返回文本节点,只需要小心你的select器,所以你知道他们将文本节点。

比如说,这个包裹里的所有文字内容都是用pre标签包装的,没有任何问题。

 jQuery("#resultTable td").content().wrap("<pre/>") 

我有同样的问题,并解决它:

码:

 $.fn.nextNode = function(){ var contents = $(this).parent().contents(); return contents.get(contents.index(this)+1); } 

用法:

 $('#my_id').nextNode(); 

就像next()但也返回文本节点。