Vorrei ottenere tutti i nodi di testo discendenti di un elemento, come una raccolta jQuery. Qual è il modo migliore per farlo?
Vorrei ottenere tutti i nodi di testo discendenti di un elemento, come una raccolta jQuery. Qual è il modo migliore per farlo?
Risposte:
jQuery non ha una funzione conveniente per questo. È necessario combinare contents()
, che darà solo nodi figlio ma include nodi di testo, con find()
, che fornisce tutti gli elementi discendenti ma nessun nodo di testo. Ecco cosa mi è venuto in mente:
var getTextNodesIn = function(el) {
return $(el).find(":not(iframe)").addBack().contents().filter(function() {
return this.nodeType == 3;
});
};
getTextNodesIn(el);
Nota: se si utilizza jQuery 1.7 o precedente, il codice sopra non funzionerà. Per risolvere questo problema, sostituirlo addBack()
con andSelf()
. andSelf()
è deprecato a favore addBack()
dell'1,8 in poi.
Questo è in qualche modo inefficiente rispetto ai metodi DOM puri e deve includere una brutta soluzione per il sovraccarico della sua contents()
funzione di jQuery (grazie a @rabidsnail nei commenti per averlo sottolineato), quindi ecco una soluzione non jQuery che utilizza una semplice funzione ricorsiva. Il includeWhitespaceNodes
parametro controlla se i nodi di testo degli spazi bianchi sono inclusi nell'output (in jQuery vengono automaticamente filtrati).
Aggiornamento: corretto bug quando includeWhitespaceNodes è errato.
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);
document.getElementById()
primo, se è questo che intendi:var div = document.getElementById("foo"); var textNodes = getTextNodesIn(div);
.contents()
comunque implica che cercherà anche attraverso l'iframe. Non vedo come potrebbe essere un bug.
Jauco ha pubblicato una buona soluzione in un commento, quindi la sto copiando qui:
$(elem)
.contents()
.filter(function() {
return this.nodeType === 3; //Node.TEXT_NODE
});
jQuery.contents()
può essere utilizzato con jQuery.filter
per trovare tutti i nodi di testo figlio. Con una piccola svolta, puoi trovare anche i nodi di testo dei nipoti. Nessuna ricorsione richiesta:
$(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>
Stavo ottenendo molti nodi di testo vuoti con la funzione di filtro accettata. Se sei interessato solo a selezionare nodi di testo che contengono spazi non bianchi, prova ad aggiungere un nodeValue
condizionale alla tua filter
funzione, come un semplice $.trim(this.nodevalue) !== ''
:
$('element')
.contents()
.filter(function(){
return this.nodeType === 3 && $.trim(this.nodeValue) !== '';
});
O per evitare strane situazioni in cui il contenuto appare come uno spazio bianco, ma non lo è (ad esempio il ­
carattere trattino morbido , nuove righe \n
, tabulazioni, ecc.), Puoi provare a usare un'espressione regolare. Ad esempio, \S
corrisponderà a tutti i caratteri non bianchi:
$('element')
.contents()
.filter(function(){
return this.nodeType === 3 && /\S/.test(this.nodeValue);
});
Se puoi supporre che tutti i bambini siano nodi Element o Text Nodes, allora questa è una soluzione.
Per ottenere tutti i nodi di testo figlio come una raccolta jquery:
$('selector').clone().children().remove().end().contents();
Per ottenere una copia dell'elemento originale con elementi secondari non di testo rimossi:
$('selector').clone().children().remove().end();
Per qualche motivo contents()
non ha funzionato per me, quindi se non ha funzionato per te, ecco una soluzione che ho creato, ho creato jQuery.fn.descendants
con l'opzione di includere nodi di testo o meno
uso
Ottieni tutti i discendenti inclusi nodi di testo e nodi di elementi
jQuery('body').descendants('all');
Ottieni tutti i discendenti che restituiscono solo nodi di testo
jQuery('body').descendants(true);
Ottieni tutti i discendenti che restituiscono solo nodi di elementi
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)
Inserisci nella versione Javascript
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)}
Versione Javascript non modificata: http://pastebin.com/cX3jMfuD
Questo è cross browser, un piccolo Array.indexOf
polyfill è incluso nel codice.
Può anche essere fatto in questo modo:
var textContents = $(document.getElementById("ElementId").childNodes).filter(function(){
return this.nodeType == 3;
});
Il codice sopra filtra i textNodes dai nodi figlio figlio diretti di un dato elemento.
se vuoi rimuovere tutti i tag, prova questo
funzione:
String.prototype.stripTags=function(){
var rtag=/<.*?[^>]>/g;
return this.replace(rtag,'');
}
utilizzo:
var newText=$('selector').html().stripTags();
Per me, il vecchio .contents()
sembra funzionare per restituire i nodi di testo, basta fare attenzione con i selettori in modo da sapere che saranno nodi di testo.
Ad esempio, questo ha avvolto tutto il contenuto testuale dei TD nella mia tabella con pre
tag e non ha avuto problemi.
jQuery("#resultTable td").content().wrap("<pre/>")
Ho avuto lo stesso problema e l'ho risolto con:
Codice:
$.fn.nextNode = function(){
var contents = $(this).parent().contents();
return contents.get(contents.index(this)+1);
}
Uso:
$('#my_id').nextNode();
È come next()
ma restituisce anche i nodi di testo.