Я хотел бы получить все потоковые текстовые узлы элемента, как коллекцию jQuery. Каков наилучший способ сделать это?
Как выбрать текстовые узлы с помощью jQuery?
Ответ 1
jQuery для этого не имеет удобной функции. Вам нужно объединить contents()
, который даст только дочерние узлы, но включает текстовые узлы, с find()
, который дает все элементы-потомки, но не текстовые узлы. Вот что я придумал:
var getTextNodesIn = function(el) {
return $(el).find(":not(iframe)").addBack().contents().filter(function() {
return this.nodeType == 3;
});
};
getTextNodesIn(el);
Примечание. Если вы используете jQuery 1.7 или ранее, код выше не будет работать. Чтобы исправить это, замените addBack()
с andSelf()
, andSelf()
устарел в пользу addBack()
с 1,8 и далее.
Это несколько неэффективно по сравнению с чистыми методами DOM и должно включать уродливое обходное решение для перегрузки jQuery его функции contents()
(благодаря @rabidsnail в комментариях для указания этого), так что это решение, отличное от jQuery, с использованием простой рекурсивной функции. Параметр includeWhitespaceNodes
определяет, включены ли в выходной текст текстовые узлы (в jQuery они автоматически отфильтровываются).
Обновление: исправлена ошибка, когда includeWhitespaceNodes является ложным.
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);
Ответ 2
Jauco опубликовал хорошее решение в комментарии, поэтому я копирую его здесь:
$(elem)
.contents()
.filter(function() {
return this.nodeType === 3; //Node.TEXT_NODE
});
Ответ 3
$('body').find('*').contents().filter(function () { return this.nodeType === 3; });
Ответ 4
jQuery.contents()
можно использовать с jQuery.filter
, чтобы найти все дочерние текстовые узлы. С небольшим завихрением вы также можете найти текстовые узлы внуков. Не требуется рекурсия:
$(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; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="test">
child text 1<br>
child text 2
<div>
grandchild text 1
<div>grand-grandchild text 1</div>
grandchild text 2
</div>
child text 3<br>
child text 4
</div>
Ответ 5
Я получал много пустых текстовых узлов с принятой функцией фильтра. Если вы заинтересованы только в выборе текстовых узлов, которые содержат не-пробелы, попробуйте добавить nodeValue
к вашей функции filter
, как простой $.trim(this.nodevalue) !== ''
:
$('element')
.contents()
.filter(function(){
return this.nodeType === 3 && $.trim(this.nodeValue) !== '';
});
Или во избежание странных ситуаций, когда содержимое выглядит как пробел, но не является (например, символ мягкого дефиса ­
, символы новой строки \n
, вкладки и т.д.), вы можете попробовать использовать регулярное выражение. Например, \S
будет соответствовать любым символам без пробелов:
$('element')
.contents()
.filter(function(){
return this.nodeType === 3 && /\S/.test(this.nodeValue);
});
Ответ 6
Если вы можете сделать предположение, что все дети являются либо узлами элементов, либо текстовыми узлами, то это одно из решений.
Чтобы получить все дочерние текстовые узлы в виде коллекции jquery:
$('selector').clone().children().remove().end().contents();
Чтобы получить копию исходного элемента с удаленными дочерними элементами:
$('selector').clone().children().remove().end();
Ответ 7
Можно также выполнить следующие действия:
var textContents = $(document.getElementById("ElementId").childNodes).filter(function(){
return this.nodeType == 3;
});
Вышеупомянутый код фильтрует текстовые узлы из дочерних дочерних узлов дочерних элементов данного элемента.
Ответ 8
По какой-то причине contents()
не работал у меня, поэтому, если это не сработало для вас, вот решение, которое я сделал, я создал jQuery.fn.descendants
с возможностью включения текстовых узлов или нет
Использование
Получить все потомки, включая текстовые узлы и узлы элементов
jQuery('body').descendants('all');
Получить все потомки, возвращающие только текстовые узлы
jQuery('body').descendants(true);
Получить все потомки, возвращающие только узлы элементов
jQuery('body').descendants();
Coffeescript Original:
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)
Drop In Javascript Version
var __indexOf=[].indexOf||function(e){for(var t=0,n=this.length;t<n;t++){if(t in this&&this[t]===e)return t}return-1}; /* indexOf polyfill ends here*/ jQuery.fn.descendants=function(e){var t,n,r,i,s,o;t=e==="all"?[1,3]:e?[3]:[1];i=[];n=function(e){var r,s,o,u,a,f;u=e.childNodes;f=[];for(s=0,o=u.length;s<o;s++){r=u[s];if(a=r.nodeType,__indexOf.call(t,a)>=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<o;s++){r=this[s];n(r)}return jQuery(i)}
Unminified версия Javascript: http://pastebin.com/cX3jMfuD
Это кросс-браузер, в код включен небольшой Array.indexOf
polyfill.
Ответ 9
если вы хотите удалить все теги, а затем попробуйте
функция:
String.prototype.stripTags=function(){
var rtag=/<.*?[^>]>/g;
return this.replace(rtag,'');
}
использование
var newText=$('selector').html().stripTags();
Ответ 10
У меня была та же проблема, и я решил:
код:
$.fn.nextNode = function(){
var contents = $(this).parent().contents();
return contents.get(contents.index(this)+1);
}
Использование:
$('#my_id').nextNode();
Походит на next()
, но также возвращает текстовые узлы.
Ответ 11
Для меня простой старый .contents()
появился, чтобы возвращать текстовые узлы, просто нужно быть осторожным с вашими селекторами, чтобы вы знали, что они будут текстовыми узлами.
Например, это обернуло все текстовое содержимое TDs в моей таблице тегами pre
и не было проблем.
jQuery("#resultTable td").content().wrap("<pre/>")