Ich möchte alle untergeordneten Textknoten eines Elements als jQuery-Auflistung erhalten. Was ist der beste Weg das zu tun?
Ich möchte alle untergeordneten Textknoten eines Elements als jQuery-Auflistung erhalten. Was ist der beste Weg das zu tun?
Antworten:
jQuery hat hierfür keine praktische Funktion. Sie müssen kombinieren contents()
, was nur untergeordnete Knoten find()
ergibt, aber Textknoten enthält, mit , was alle untergeordneten Elemente, aber keine Textknoten ergibt. Folgendes habe ich mir ausgedacht:
var getTextNodesIn = function(el) {
return $(el).find(":not(iframe)").addBack().contents().filter(function() {
return this.nodeType == 3;
});
};
getTextNodesIn(el);
Hinweis: Wenn Sie jQuery 1.7 oder früher verwenden, funktioniert der obige Code nicht. Um dies zu beheben, ersetzen Sie addBack()
durch andSelf()
. andSelf()
wird zugunsten von addBack()
ab 1,8 abgelehnt .
Dies ist im Vergleich zu reinen DOM-Methoden etwas ineffizient und muss eine hässliche Problemumgehung für die Überladung seiner contents()
Funktion durch jQuery enthalten (dank @rabidsnail in den Kommentaren, um darauf hinzuweisen). Daher handelt es sich hier um eine Nicht-jQuery-Lösung, die eine einfache rekursive Funktion verwendet. Der includeWhitespaceNodes
Parameter steuert, ob Whitespace-Textknoten in der Ausgabe enthalten sind oder nicht (in jQuery werden sie automatisch herausgefiltert).
Update: Fehler behoben, wenn includeWhitespaceNodes falsch ist.
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()
zuerst anrufen , wenn Sie das meinen:var div = document.getElementById("foo"); var textNodes = getTextNodesIn(div);
.contents()
sowieso impliziert, dass es auch den Iframe durchsuchen wird. Ich sehe nicht ein, wie es ein Fehler sein könnte.
Jauco hat in einem Kommentar eine gute Lösung gepostet, daher kopiere ich sie hier:
$(elem)
.contents()
.filter(function() {
return this.nodeType === 3; //Node.TEXT_NODE
});
jQuery.contents()
kann verwendet werden jQuery.filter
, um alle untergeordneten Textknoten zu finden. Mit einer kleinen Drehung können Sie auch Textknoten für Enkelkinder finden. Keine Rekursion erforderlich:
$(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>
Ich habe viele leere Textknoten mit der akzeptierten Filterfunktion erhalten. Wenn Sie nur daran interessiert sind Textknoten in der Auswahl , die kein Leerzeichen enthalten, versuchen , eine Zugabe nodeValue
bedingte zu Ihrer filter
Funktion, wie eine einfache $.trim(this.nodevalue) !== ''
:
$('element')
.contents()
.filter(function(){
return this.nodeType === 3 && $.trim(this.nodeValue) !== '';
});
Um seltsame Situationen zu vermeiden, in denen der Inhalt wie ein Leerzeichen aussieht, dies jedoch nicht ist (z. B. das weiche Bindestrichzeichen ­
, Zeilenumbrüche \n
, Tabulatoren usw.), können Sie versuchen, einen regulären Ausdruck zu verwenden. Entspricht beispielsweise \S
allen Nicht-Leerzeichen:
$('element')
.contents()
.filter(function(){
return this.nodeType === 3 && /\S/.test(this.nodeValue);
});
Wenn Sie davon ausgehen können, dass alle untergeordneten Elemente entweder Elementknoten oder Textknoten sind, ist dies eine Lösung.
So rufen Sie alle untergeordneten Textknoten als JQuery-Sammlung ab:
$('selector').clone().children().remove().end().contents();
So erhalten Sie eine Kopie des Originalelements, bei der nicht untergeordnete Textelemente entfernt wurden:
$('selector').clone().children().remove().end();
Aus irgendeinem Grund contents()
hat es bei mir nicht funktioniert. Wenn es bei Ihnen nicht funktioniert hat, habe ich eine Lösung erstellt, die ich jQuery.fn.descendants
mit der Option erstellt habe, Textknoten einzuschließen oder nicht
Verwendungszweck
Holen Sie sich alle Nachkommen einschließlich Textknoten und Elementknoten
jQuery('body').descendants('all');
Lassen Sie alle Nachkommen nur Textknoten zurückgeben
jQuery('body').descendants(true);
Lassen Sie alle Nachkommen nur Elementknoten zurückgeben
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)}
Nicht minimierte Javascript-Version: http://pastebin.com/cX3jMfuD
Dies ist browserübergreifend, eine kleine Array.indexOf
Polyfüllung ist im Code enthalten.
Kann auch so gemacht werden:
var textContents = $(document.getElementById("ElementId").childNodes).filter(function(){
return this.nodeType == 3;
});
Der obige Code filtert die textNodes von direkten untergeordneten untergeordneten Knoten eines bestimmten Elements.
Wenn Sie alle Tags entfernen möchten, versuchen Sie dies
Funktion:
String.prototype.stripTags=function(){
var rtag=/<.*?[^>]>/g;
return this.replace(rtag,'');
}
Verwendungszweck:
var newText=$('selector').html().stripTags();
Für mich .contents()
schien einfach alt zu funktionieren, um die Textknoten zurückzugeben. Sie müssen nur vorsichtig mit Ihren Selektoren sein, damit Sie wissen, dass es sich um Textknoten handelt.
Dies hat beispielsweise den gesamten Textinhalt der TDs in meiner Tabelle mit pre
Tags versehen und hatte keine Probleme.
jQuery("#resultTable td").content().wrap("<pre/>")
Ich hatte das gleiche Problem und löste es mit:
Code:
$.fn.nextNode = function(){
var contents = $(this).parent().contents();
return contents.get(contents.index(this)+1);
}
Verwendungszweck:
$('#my_id').nextNode();
Ist wie, gibt next()
aber auch die Textknoten zurück.