Usando .text () para recuperar somente texto não nested em tags filhas

Se eu tenho html assim:

  • This is some text First span text Second span text
  • Eu estou tentando usar .text() para recuperar apenas a seqüência de caracteres “Isso é algum texto“, mas se eu fosse dizer $('#list-item').text() , eu recebo “Este é um período de textFirst textSecond span text “.

    Existe uma maneira de obter (e possivelmente remover, por meio de algo como .text("") ) apenas o texto livre dentro de uma tag, e não o texto dentro de suas tags .text("") ?

    O HTML não foi escrito por mim, então é com isso que tenho que trabalhar. Eu sei que seria simples apenas colocar o texto em tags ao escrever o html, mas novamente, o html é pré-escrito.

    Gostei desta implementação reutilizável com base no método clone() encontrado aqui para obter apenas o texto dentro do elemento pai.

    Código fornecido para fácil referência:

     $("#foo") .clone() //clone the element .children() //select all the children .remove() //remove all the children .end() //again go back to selected element .text(); 

    Resposta simples:

     $("#listItem").contents().filter(function(){ return this.nodeType == 3; })[0].nodeValue = "The text you want to replace with" 

    Isso parece um caso de uso excessivo de jquery para mim. O seguinte irá pegar o texto ignorando os outros nós:

     document.getElementById("listItem").childNodes[0]; 

    Você precisará cortar isso, mas você terá o que deseja em uma linha fácil.

    EDITAR

    O acima irá obter o nó de texto . Para obter o texto real, use isto:

     document.getElementById("listItem").childNodes[0].nodeValue; 

    Mais fácil e mais rápido:

     $("#listItem").contents().get(0).nodeValue 

    Semelhante à resposta aceita, mas sem clonagem:

     $("#foo").contents().not($("#foo").children()).text(); 

    E aqui está um plugin jQuery para essa finalidade:

     $.fn.immediateText = function() { return this.contents().not(this.children()).text(); }; 

    Aqui está como usar este plugin:

     $("#foo").immediateText(); // get the text without children 

    não é o código:

     var text = $('#listItem').clone().children().remove().end().text(); 

    apenas se tornando jQuery por amor de jQuery? Quando operações simples envolvem muitos comandos encadeados e muito processamento (desnecessário), talvez seja hora de escrever uma extensão do jQuery:

     (function ($) { function elementText(el, separator) { var textContents = []; for(var chld = el.firstChild; chld; chld = chld.nextSibling) { if (chld.nodeType == 3) { textContents.push(chld.nodeValue); } } return textContents.join(separator); } $.fn.textNotChild = function(elementSeparator, nodeSeparator) { if (arguments.length<2){nodeSeparator="";} if (arguments.length<1){elementSeparator="";} return $.map(this, function(el){ return elementText(el,nodeSeparator); }).join(elementSeparator); } } (jQuery)); 

    chamar:

     var text = $('#listItem').textNotChild(); 

    os argumentos são no caso de um cenário diferente ser encontrado, como

     
  • some textmore textagain more
  • second textmore textagain more
  • var text = $("li").textNotChild(".....","");

    texto terá valor:

     some textagain more.....second textagain more 

    Terá que ser algo adaptado às necessidades, que dependem da estrutura com a qual você é apresentado. Para o exemplo que você forneceu, isso funciona:

     $(document).ready(function(){ var $tmp = $('#listItem').children().remove(); $('#listItem').text('').append($tmp); }); 

    Demonstração: http://jquery.nodnod.net/cases/2385/run

    Mas é bastante dependente da marcação ser semelhante ao que você postou.

    Tente isto:

     $('#listItem').not($('#listItem').children()).text() 
     $($('#listItem').contents()[0]).text() 

    Pequena variante da resposta de Stuart.

    ou com get()

     $($('#listItem').contents().get(0)).text() 

    Esta é uma pergunta antiga, mas a resposta principal é muito ineficiente. Aqui está uma solução melhor:

     $.fn.myText = function() { var str = ''; this.contents().each(function() { if (this.nodeType == 3) { str += this.textContent || this.innerText || ''; } }); return str; }; 

    E faça isso:

     $("#foo").myText(); 
     jQuery.fn.ownText = function () { return $(this).contents().filter(function () { return this.nodeType === Node.TEXT_NODE; }).text(); }; 

    Eu presumo que esta seria uma boa solução também – se você quiser obter o conteúdo de todos os nós de texto que são filhos diretos do elemento selecionado.

     $(selector).contents().filter(function(){ return this.nodeType == 3; }).text(); 

    Nota: a documentação do jQuery usa código semelhante para explicar a function de conteúdo: https://api.jquery.com/contents/

    PS Há também uma maneira um pouco mais feia de fazer isso, mas isso mostra mais profundamente como as coisas funcionam e permite o separador personalizado entre nós de texto (talvez você queira uma quebra de linha)

     $(selector).contents().filter(function(){ return this.nodeType == 3; }).map(function() { return this.nodeValue; }).toArray().join(""); 

    basta colocá-lo em um

    ou e pegue esse $ (‘# listItem font’). text ()

    Primeira coisa que veio à mente

     
  • This is some text First span text Second span text
  • Eu criei uma solução específica que deveria ser muito mais eficiente do que a clonagem e modificação do clone. Essa solução só funciona com as duas reservas a seguir, mas deve ser mais eficiente do que a solução aceita atualmente:

    1. Você está recebendo apenas o texto
    2. O texto que você deseja extrair está antes dos elementos filhos

    Com isso dito, aqui está o código:

     // 'element' is a jQuery element function getText(element) { var text = element.text(); var childLength = element.children().text().length; return text.slice(0, text.length - childLength); } 

    Proponho usar o createTreeWalker para encontrar todos os elementos de texto não anexados a elementos html (esta function pode ser usada para estender o jQuery):

     function textNodesOnlyUnder(el) { var resultSet = []; var n = null; var treeWalker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, function (node) { if (node.parentNode.id == el.id && node.textContent.trim().length != 0) { return NodeFilter.FILTER_ACCEPT; } return NodeFilter.FILTER_SKIP; }, false); while (n = treeWalker.nextNode()) { resultSet.push(n); } return resultSet; } window.onload = function() { var ele = document.getElementById('listItem'); var textNodesOnly = textNodesOnlyUnder(ele); var resultingText = textNodesOnly.map(function(val, index, arr) { return 'Text element N. ' + index + ' --> ' + val.textContent.trim(); }).join('\n'); document.getElementById('txtArea').value = resultingText; } 
     
  • This is some text First span text Second span text
  • Assim como a pergunta, eu estava tentando extrair texto para fazer alguma substituição de expressão regular do texto, mas estava tendo problemas onde meus elementos internos (isto é: ,

    , , etc.) também estavam removido.

    O código a seguir parece funcionar bem e resolveu todos os meus problemas.

    Ele usa algumas das respostas fornecidas aqui, mas em particular, apenas replaceá o texto quando o elemento for de nodeType === 3 .

     $(el).contents().each(function() { console.log(" > Content: %s [%s]", this, (this.nodeType === 3)); if (this.nodeType === 3) { var text = this.textContent; console.log(" > Old : '%s'", text); regex = new RegExp("\\[\\[" + rule + "\\.val\\]\\]", "g"); text = text.replace(regex, value); regex = new RegExp("\\[\\[" + rule + "\\.act\\]\\]", "g"); text = text.replace(regex, actual); console.log(" > New : '%s'", text); this.textContent = text; } }); 

    O que o acima faz é percorrer todos os elementos do el dado (que foi obtido simplesmente com $("div.my-class[name='some-name']"); . Para cada elemento interno, ele basicamente os ignora Para cada parte do texto (conforme determinado por if (this.nodeType === 3) ), será aplicada a substituição de if (this.nodeType === 3) apenas a esses elementos.

    A porção this.textContent = text simplesmente substitui o texto substituído, que no meu caso, eu procurava tokens como [[min.val]] , [[max.val]] , etc.

    Este trecho de código curto ajudará qualquer um que tente fazer o que a pergunta estava pedindo … e um pouco mais.

    Este é um bom caminho para mim

      var text = $('#listItem').clone().children().remove().end().text(); 

    Você pode tentar isso

     alert(document.getElementById('listItem').firstChild.data) 

    Para poder cortar o resultado, use o DotNetWala assim:

     $("#foo") .clone() //clone the element .children() //select all the children .remove() //remove all the children .end() //again go back to selected element .text() .trim(); 

    Descobri que usar a versão mais curta como document.getElementById("listItem").childNodes[0] não funciona com trim () do jQuery.

    Use uma condição extra para verificar se innerHTML e innerText são os mesmos. Somente nesses casos, substitua o texto.

     $(function() { $('body *').each(function () { console.log($(this).html()); console.log($(this).text()); if($(this).text() === "Search" && $(this).html()===$(this).text()) { $(this).html("Find"); } }) }) 

    http://jsfiddle.net/7RSGh/

    Isso não foi testado, mas acho que você pode tentar algo assim:

      $('#listItem').not('span').text(); 

    http://api.jquery.com/not/

    Eu não sou um especialista em jquery, mas que tal

     $('#listItem').children().first().text()