Использование .text() для извлечения только текста, не вложенного в дочерние теги

Если у меня есть html:

<li id="listItem">
    This is some text
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>

Я пытаюсь использовать .text() для извлечения только строки "Это какой-то текст", но если бы я сказал $('#list-item').text(), я получаю "Это текст textFirst span textSecond span".

Есть ли способ получить (и, возможно, удалить через нечто вроде .text("")) только свободный текст внутри тега, а не текст в его дочерних тегах?

HTML не был написан мной, поэтому я должен работать. Я знаю, что было бы просто просто обернуть текст в тегах при написании html, но опять же, html предварительно написан.

+349
09 авг. '10 в 17:07
источник поделиться
24 ответа

Мне понравилась эта многократно используемая реализация, основанная на методе clone() найденном здесь, чтобы получить только текст внутри родительского элемента.

Код предоставлен для удобства пользования:

$("#foo")
    .clone()    //clone the element
    .children() //select all the children
    .remove()   //remove all the children
    .end()  //again go back to selected element
    .text();
+481
13 янв. '12 в 13:45
источник

Связанные вопросы


Похожие вопросы

Простой ответ:

$("#listItem").contents().filter(function(){ 
  return this.nodeType == 3; 
})[0].nodeValue = "The text you want to replace with" 
+337
07 февр. '13 в 15:53
источник

Это похоже на случай чрезмерного использования jquery для меня. Следующее возьмет текст, игнорируя другие узлы:

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

Вам нужно обрезать это, но вы получите то, что хотите, в одной простой линии.

ИЗМЕНИТЬ

Вышеприведенный текст получит node. Чтобы получить фактический текст, используйте это:

document.getElementById("listItem").childNodes[0].nodeValue;
+128
09 авг. '10 в 17:58
источник

Проще и быстрее:

$("#listItem").contents().get(0).nodeValue
+58
01 мар. '14 в 17:30
источник

Подобно принятому ответу, но без клонирования:

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

И для этого используется плагин jQuery:

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

Вот как использовать этот плагин:

$("#foo").immediateText(); // get the text without children
+26
23 авг. '15 в 18:28
источник

Попробуйте следующее:

$('#listItem').not($('#listItem').children()).text()
+8
05 янв. '15 в 13:02
источник

не является кодом:

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

просто становится jQuery для jQuery саке? Когда простые операции включают в себя множество цепочечных команд и такую ​​(ненужную) обработку, возможно, пришло время написать расширение 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));

для вызова:

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

аргументы в случае возникновения другого сценария, например

<li>some text<a>more text</a>again more</li>
<li>second text<a>more text</a>again more</li>

var text = $("li").textNotChild(".....","<break>");

текст будет иметь значение:

some text<break>again more.....second text<break>again more
+7
29 авг. '12 в 22:47
источник

Это должно быть нечто, соответствующее потребностям, которые зависят от структуры, которую вы представили. Для примера, который вы предоставили, это работает:

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

Демо: http://jquery.nodnod.net/cases/2385/run

Но это довольно зависит от того, что разметка похожа на то, что вы разместили.

+6
09 авг. '10 в 17:18
источник
$($('#listItem').contents()[0]).text()

Короткий вариант Ответ Стюарта.

или с get()

$($('#listItem').contents().get(0)).text()
+4
31 авг. '15 в 22:02
источник
jQuery.fn.ownText = function () {
    return $(this).contents().filter(function () {
        return this.nodeType === Node.TEXT_NODE;
    }).text();
};
+3
16 авг. '17 в 8:12
источник

Я предполагаю, что это тоже прекрасное решение - если вы хотите получить содержимое всех текстовых узлов, которые являются прямыми дочерними элементами выбранного элемента.

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

Примечание. Документация jQuery использует аналогичный код для объяснения функции содержимого: https://api.jquery.com/contents/

P.S. Там также немного уродливый способ сделать это, но это показывает более подробно, как все работает, и позволяет настраивать разделитель между текстовыми узлами (возможно, вы хотите, чтобы там была разбита строка)

$(selector).contents().filter(function(){ return this.nodeType == 3; }).map(function() { return this.nodeValue; }).toArray().join("");
+2
02 авг. '16 в 16:29
источник

Это старый вопрос, но главный ответ очень неэффективен. Здесь лучшее решение:

$.fn.myText = function() {
    var str = '';

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

    return str;
};

И просто сделайте это:

$("#foo").myText();
+2
22 июл. '15 в 21:07
источник

Если index позиции текстового узла фиксирован среди его братьев и сестер, вы можете использовать

$('parentselector').contents().eq(index).text()
+1
17 янв. '19 в 2:56
источник

Поскольку у меня пока недостаточно репутации, чтобы комментировать, и я не хочу, чтобы знания были потеряны (надеюсь, это поможет кому-то еще), сочетание ответа macio.Jun, ответа RegExp и iStranger для замены textNode на HTML в JavaScript? позволил мне искать текстовые узлы для строки и заменять все вхождения ссылками.

0
20 июн. '19 в 7:17
источник

Точно так же, как вопрос, я пытался извлечь текст, чтобы сделать некоторую подстановку текста в регулярном выражении, но у меня были проблемы, когда мои внутренние элементы (то есть: <i>, <div>, <span> и т.д.) Также получали удален.

Следующий код, кажется, работает хорошо и решил все мои проблемы.

Он использует некоторые ответы, представленные здесь, но, в частности, будет заменять текст только тогда, когда элемент имеет 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;
  }
});

То, что сделано выше, это циклическое прохождение всех элементов данного el (которое было просто получено с помощью $("div.my-class[name='some-name']"); Для каждого внутреннего элемента оно в основном игнорирует их Для каждой части текста (как определено в if (this.nodeType === 3)) будет применена замена регулярного выражения только к этим элементам.

Часть this.textContent = text просто заменяет замещенный текст, который в моем случае я искал токены типа [[min.val]], [[max.val]] и т.д.

Эта выдержка из короткого кода поможет любому, кто пытается сделать то, о чем спрашивал вопрос... и немного больше.

0
27 мар. '18 в 4:33
источник

просто поместите его в <p> или <font> и возьмите этот $('# listItem font'). text()

Первое, что пришло в голову

<li id="listItem">
    <font>This is some text</font>
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>
0
09 авг. '10 в 17:12
источник

Я придумал конкретное решение, которое должно быть намного более эффективным, чем клонирование и модификация клона. Это решение работает только со следующими двумя оговорками, но должно быть более эффективным, чем принятое в настоящее время решение:

  • Вы получаете только текст
  • Текст, который вы хотите извлечь, находится перед дочерними элементами

С учетом сказанного здесь приведен код:

// '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);
}
0
16 июл. '14 в 0:19
источник

Я предлагаю использовать createTreeWalker, чтобы найти все элементы текста, не прикрепленные к элементам html (эта функция может использоваться для расширения 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;
}
<li id="listItem">
    This is some text
    <span id="firstSpan">First span text</span>
    <span id="secondSpan">Second span text</span>
</li>
<textarea id="txtArea" style="width: 400px;height: 200px;"></textarea>
0
17 мар. '16 в 13:34
источник

Это хороший способ для меня

   var text  =  $('#listItem').clone().children().remove().end().text();
-1
10 февр. '12 в 7:03
источник

Чтобы иметь возможность обрезать результат, используйте DotNetWala следующим образом:

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

Я узнал, что использование более короткой версии, такой как document.getElementById("listItem").childNodes[0], не будет работать с jQuery trim().

-1
02 окт. '14 в 19:49
источник

Вы можете попробовать это

alert(document.getElementById('listItem').firstChild.data)
-1
20 авг. '13 в 4:51
источник

Используйте дополнительное условие для проверки того, являются ли innerHTML и innerText одинаковыми. Только в этих случаях замените текст.

$(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/

-2
11 апр. '13 в 13:10
источник

Я не эксперт jquery, но как насчет

$('#listItem').children().first().text()
-3
17 мар. '16 в 8:54
источник

Это не проверено, но я думаю, что вы можете попробовать что-то вроде этого:

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

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

-4
09 авг. '10 в 17:20
источник

Посмотрите другие вопросы по меткам или Задайте вопрос