Como faço para selecionar nós de texto com jQuery?

Eu gostaria de obter todos os nós de texto descendente de um elemento, como uma coleção jQuery. Qual o melhor jeito pra fazer isso?

O jQuery não tem uma function conveniente para isso. Você precisa combinar contents() , que dará apenas nós filho, mas inclui nós de texto, com find() , que fornece todos os elementos descendentes, mas não nós de texto. Aqui está o que eu fiz:

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

Nota: Se você estiver usando o jQuery 1.7 ou anterior, o código acima não funcionará. Para corrigir isso, substitua addBack() por andSelf() . andSelf() é preterido em favor de addBack() de 1.8 em diante.

Isso é um pouco ineficiente em comparação com methods DOM puros e tem que include uma solução feia para a sobrecarga do jQuery de sua function contents() (assim como @rabidsnail nos comentários para apontar isso), então aqui está a solução não-jQuery usando uma recursion simples function. O parâmetro includeWhitespaceNodes controla se os nós de texto em espaço em branco estão ou não incluídos na saída (no jQuery, eles são automaticamente filtrados).

Atualização: Corrigido o erro quando includeWhitespaceNodes é falso.

 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 postou uma boa solução em um comentário, então estou copiando aqui:

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

jQuery.contents() pode ser usado com jQuery.filter para encontrar todos os nós de texto filho. Com um pequeno toque, você pode encontrar nodos de texto netos também. Nenhuma recursion necessária:

 $(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; } 
  
child text 1
child text 2
grandchild text 1
grand-grandchild text 1
grandchild text 2
child text 3
child text 4

Eu estava recebendo muitos nós de texto vazios com a function de filtro aceita. Se você estiver interessado apenas em selecionar nós de texto que contenham espaços não nodeValue , tente adicionar um nodeValue condicional à sua function de filter , como um simples $.trim(this.nodevalue) !== '' :

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

http://jsfiddle.net/ptp6m97v/

Ou, para evitar situações estranhas em que o conteúdo se pareça com espaço em branco, mas não é (por exemplo, o caractere de hífen ­ , novas linhas, \n , guias etc.), você pode tentar usar uma expressão regular. Por exemplo, \S corresponderá a qualquer caractere que não seja espaço em branco:

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

Se você puder supor que todos os filhos são nós de elemento ou nós de texto, essa é uma solução.

Para obter todos os nós de texto filho como uma coleção jquery:

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

Para obter uma cópia do elemento original com filhos que não são de texto removidos:

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

Também pode ser feito assim:

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

O código acima filtra os textNodes dos nós filhos diretos filhos de um determinado elemento.

Por alguma razão, o contents() não funcionou para mim, por isso, se não funcionou para você, aqui está uma solução que fiz, criei jQuery.fn.descendants com a opção de include nós de texto ou não

Uso


Obter todos os descendentes, incluindo nós de texto e nós de elemento

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

Obter todos os descendentes que retornam apenas nós de texto

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

Obter todos os descendentes que retornam apenas nós de elemento

 jQuery('body').descendants(); 

Original do Coffeescript :

 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) 

Soltar na versão Javascript

 var __indexOf=[].indexOf||function(e){for(var t=0,n=this.length;t=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 

Versão de Javascript não-unificada: http://pastebin.com/cX3jMfuD

Este é cross browser, um pequeno Array.indexOf Array.indexOf está incluído no código.

se você quiser remover todas as tags, tente isso

function:

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

uso:

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

Para mim, simples .contents() apareceu para trabalhar para retornar os nós de texto, só tem que ter cuidado com seus seletores para que você saiba que eles serão nós de texto.

Por exemplo, isso envolveu todo o conteúdo de texto dos TDs na minha tabela com pre tags e não teve problemas.

 jQuery("#resultTable td").content().wrap("

")

Eu tive o mesmo problema e resolvi com:

Código:

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

Uso:

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

É como next() mas também retorna os nós de texto.