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