Использование .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 предварительно написан.

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

ИЗМЕНИТЬ

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

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

Ответ 4

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

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

Ответ 5

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

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

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

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

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

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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

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

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

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

Ответ 9

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

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

или с get()

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

Ответ 10

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

Ответ 11

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

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

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

    return str;
};

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

$("#foo").myText();

Ответ 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("");

Ответ 13

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

$('parentselector').contents().eq(index).text()

Ответ 14

просто поместите его в <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>

Ответ 15

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

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

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

// '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);
}

Ответ 16

Я предлагаю использовать 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>

Ответ 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]] и т.д.

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

Ответ 18

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

Ответ 19

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

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

Ответ 20

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

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

Ответ 21

Чтобы иметь возможность обрезать результат, используйте 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().

Ответ 22

Используйте дополнительное условие для проверки того, являются ли 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/

Ответ 23

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

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

Ответ 24

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

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

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