Wie kann ich den Text eines Elements ändern, ohne seine untergeordneten Elemente zu ändern?

118

Ich möchte den Text des Elements dynamisch aktualisieren:

<div>
   **text to change**
   <someChild>
       text that should not change
   </someChild>
   <someChild>
       text that should not change
   </someChild>
</div>

Ich bin neu bei jQuery, daher scheint diese Aufgabe für mich eine große Herausforderung zu sein. Könnte mich jemand auf eine zu verwendende Funktion / Auswahl hinweisen?

Wenn es möglich ist, möchte ich dies tun, ohne einen neuen Container für den Text hinzuzufügen, den ich ändern muss.

ika
quelle
7
"Wenn es möglich ist, würde ich es gerne tun, ohne einen neuen Container für den Text hinzuzufügen, den ich ändern muss." - Ja wirklich? Weil es mit einem Container viel einfacher wäre.
Paul D. Waite
Leute, ich habe mir die ursprüngliche Frage angesehen und glaube nicht, dass das OP etwas über untergeordnete Elemente gesagt hat ...
Šime Vidas
Nach W3-Standards kann div nicht einmal Textknoten haben (wenn ich mich richtig erinnere). Ein Textcontainer wie <p>, <h1> usw. sollte hinzugefügt werden.
Mark Baijens
2
@Mark: möglicherweise in (X) HTML Strict, aber nicht mehr. (HTML5 ist jetzt hier.)
Paul D. Waite
@ Matt Ball: In HTML gibt es Span-Tags anstelle von someChild.
Ika

Antworten:

74

Mark hat mit jQuery eine bessere Lösung , aber Sie können dies möglicherweise auch in normalem JavaScript tun.

In Javascript childNodesgibt Ihnen die Eigenschaft alle untergeordneten Knoten eines Elements, einschließlich Textknoten.

Wenn Sie also wussten, dass der zu ändernde Text immer das erste im Element sein würde, dann geben Sie zB diesen HTML-Code an:

<div id="your_div">
   **text to change**
   <p>
       text that should not change
   </p>
   <p>
       text that should not change
   </p>
</div>

Sie könnten dies tun:

var your_div = document.getElementById('your_div');

var text_to_change = your_div.childNodes[0];

text_to_change.nodeValue = 'new text';

Natürlich können Sie immer noch jQuery verwenden, um <div>das zuerst auszuwählen (dh var your_div = $('your_div').get(0);).

Paul D. Waite
quelle
1
Der Textknoten muss nicht ersetzt werden. Ändern Sie einfach das vorhandene dataoder nodeValueEigentum.
Tim Down
@ Tim: Ah, ich dachte, es muss einen einfacheren Weg geben. Nie viel JavaScript gemacht, bevor jQuery kam. Prost, ich werde die Antwort entsprechend bearbeiten.
Paul D. Waite
11
Eine aktuellere Umsetzung dieser Antwort wäre also$('#yourDivId')[0].childNodes[0].nodeValue = 'New Text';
Dean Martin
Mit Abstand die kürzeste und einfachste Lösung - stackoverflow.com/a/54365288/4769218
Silver
1
"Möglicherweise können Sie dies auch in
normalem
64

Update 2018

Da dies eine sehr beliebte Antwort ist, habe ich beschlossen, sie ein wenig zu aktualisieren und zu verschönern, indem ich den Textknoten-Selektor als Plugin zu jQuery hinzufügte.

Im folgenden Snippet sehen Sie, dass ich eine neue jQuery-Funktion definiere, die alle (und nur) die textNodes abruft. Sie können diese Funktion auch mit beispielsweise der first()Funktion verketten. Ich schneide den Textknoten ab und überprüfe, ob er nach dem Zuschneiden nicht leer ist, da Leerzeichen, Tabulatoren, neue Zeilen usw. auch als Textknoten erkannt werden. Wenn Sie diese Knoten auch benötigen, entfernen Sie diese einfach aus der if-Anweisung in der jQuery-Funktion.

Ich habe ein Beispiel hinzugefügt, wie der erste Textknoten ersetzt wird und wie alle Textknoten ersetzt werden.

Dieser Ansatz erleichtert das Lesen des Codes und die mehrfache Verwendung für verschiedene Zwecke.

Das Update 2017 (adrach) sollte auch weiterhin funktionieren, wenn Sie dies bevorzugen.

Als jQuery-Erweiterung

Javascript (ES) eqivilant


Update 2017 (adrach):

Es sieht so aus, als hätten sich einige Dinge geändert, seit dies veröffentlicht wurde. Hier ist eine aktualisierte Version

$("div").contents().filter(function(){ return this.nodeType == 3; }).first().replaceWith("change text");

Ursprüngliche Antwort (funktioniert nicht für aktuelle Versionen)

$("div").contents().filter(function(){ return this.nodeType == 3; })
.filter(':first').text("change text");

Quelle: http://api.jquery.com/contents/

Mark Baijens
quelle
Aha! Ich wusste, dass es irgendwo eine clevere jQuery-Funktion geben würde. Das einzige Problem mit der Lösung, die Sie geschrieben haben, ist, dass jeder Textknoten den nächsten Text erhält (z. B. einschließlich derjenigen in untergeordneten Elementen). Ich denke, es wäre nicht zu schwer, es einzuschränken?
Paul D. Waite
10
Ich hatte einige Probleme mit der Verwendung .filter(':first'), aber .first()stattdessen hat die Verwendung für mich funktioniert. Vielen Dank!
Hollaburoo
16
Dies funktioniert bei mir nicht mit .text()(siehe diese jsfiddle ), sondern mit .replaceWith()( jsfiddle hier ).
Magicexex
2
Dies funktioniert für mich, hässlich wie es ist textObject = $ (myNode) .contents (). Filter (function () {return this.nodeType == 3;}) [0] $ (textObject) .replaceWith ("mein Text" );
Maragues
Jeder, der neugierig nodeType=3ist, ist der mittlere Filterknotentyp "TEXT", w3schools.com/jsref/prop_node_nodetype.asp für weitere Informationen
ktutnik
53

Siehe In Aktion

Markup:

$(function() {
  $('input[type=button]').one('click', function() {
    var cache = $('#parent').children();
    $('#parent').text('Altered Text').append(cache);
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">Some text
  <div>Child1</div>
  <div>Child2</div>
  <div>Child3</div>
  <div>Child4</div>
</div>
<input type="button" value="alter text" />


quelle
6
Mit Abstand die beste Lösung, die mir begegnet ist. Elegant und einfach.
Yoav Kadosh
3
Dadurch wird jedoch die Reihenfolge der Knoten nicht beibehalten. Wenn sich der Text beispielsweise zuerst am Ende des Elements befand, befand er sich jetzt am Anfang.
Matt
Die Reihenfolge wird nicht beibehalten, aber in den meisten Fällen möchten Sie den Text als ersten oder letzten Knoten. Wenn append () nicht das gewünschte Ergebnis erzielt, versuchen Sie prepend (), wenn die vorhandenen untergeordneten Elemente vor dem Text angezeigt werden sollen.
Sensei
Mit Abstand die kürzeste und einfachste Lösung - stackoverflow.com/a/54365288/4769218
Silver
11
<div id="divtochange">
    **text to change**
    <div>text that should not change</div>
    <div>text that should not change</div>
</div>
$(document).ready(function() {
    $("#divtochange").contents().filter(function() {
            return this.nodeType == 3;
        })
        .replaceWith("changed text");
});

Dies ändert nur den ersten Textknoten

ilkin
quelle
9

Schließen Sie einfach den zu ändernden Text in eine Spanne mit einer Klasse ein, die Sie auswählen möchten.

Beantwortet nicht unbedingt Ihre Frage, die ich kenne, aber wahrscheinlich eine bessere Codierungspraxis. Halten Sie die Dinge sauber und einfach

<div id="header">
   <span class="my-text">**text to change**</span>
   <div>
       text that should not change
   </div>
   <div>
       text that should not change
   </div>
</div>

Voilà!

$('#header .mytext').text('New text here')
MrBojangles
quelle
Dies ist die beste Lösung!
Sleek Geek
5

Für den von Ihnen erwähnten speziellen Fall:

<div id="foo">
   **text to change**
   <someChild>
       text that should not change
   </someChild>
   <someChild>
       text that should not change
   </someChild>
</div>

... das ist sehr einfach:

var div = document.getElementById("foo");
div.firstChild.data = "New text";

Sie geben nicht an, wie Sie dies verallgemeinern möchten. Wenn Sie beispielsweise den Text des ersten Textknotens innerhalb von ändern möchten <div>, können Sie Folgendes tun:

var child = div.firstChild;
while (child) {
    if (child.nodeType == 3) {
        child.data = "New text";
        break;
    }
    child = child.nextSibling;
}
Tim Down
quelle
2

$.fn.textPreserveChildren = function(text) {
  return this.each(function() {
    return $(this).contents().filter(function() {
      return this.nodeType == 3;
    }).first().replaceWith(text);
  })
}

setTimeout(function() {
  $('.target').textPreserveChildren('Modified');
}, 2000);
.blue {
  background: #77f;
}
.green {
  background: #7f7;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

<div class="target blue">Outer text
  <div>Nested element</div>
</div>

<div class="target green">Another outer text
  <div>Another nested element</div>
</div>

geg
quelle
1

Hier ist noch eine andere Methode: http://jsfiddle.net/qYUBp/7/

HTML

<div id="header">
   **text to change**
   <div>
       text that should not change
   </div>
   <div>
       text that should not change
   </div>
</div>

JQUERY

var tmp=$("#header>div").html();
$("#header").text("its thursday").append(tmp);
Yasser Shaikh
quelle
1

Viele gute Antworten hier, aber sie behandeln nur einen Textknoten mit Kindern. In meinem Fall musste ich alle Textknoten bearbeiten und HTML-Kinder ignorieren, ABER DIE BESTELLUNG ERHALTEN.

Wenn wir also einen Fall wie diesen haben:

<div id="parent"> Some text
    <div>Child1</div>
    <div>Child2</div>
    and some other text
    <div>Child3</div>
    <div>Child4</div>
    and here we are again
</div>

Wir können den folgenden Code verwenden, um nur den Text zu ändern UND DIE BESTELLUNG ZU ERHALTEN

    $('#parent').contents().filter(function() {
        return this.nodeType == Node.TEXT_NODE && this.nodeValue.trim() != '';
    }).each(function() {
    		//You can ignore the span class info I added for my particular application.
        $(this).replaceWith(this.nodeValue.replace(/(\w+)/g,"<span class='IIIclassIII$1' onclick='_mc(this)' onmouseover='_mr(this);' onmouseout='_mt(this);'>$1X</span>"));
	});
<script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
<div id="parent"> Some text
    <div>Child1</div>
    <div>Child2</div>
    and some other text
    <div>Child3</div>
    <div>Child4</div>
    and here we are again
</div>

Hier ist der jsfiddle davon funktioniert

user1254723
quelle
0

Ich denke, Sie suchen nach .prependTo ().

http://api.jquery.com/prependTo/

Wir können auch ein Element auf der Seite auswählen und in ein anderes einfügen:

$ ('h2'). prependTo ($ ('. container'));

Wenn ein auf diese Weise ausgewähltes Element an einer anderen Stelle eingefügt wird, wird es in das Ziel verschoben (nicht geklont):

<div class="container">  
  <h2>Greetings</h2>
  <div class="inner">Hello</div>
  <div class="inner">Goodbye</div> 
</div>

Wenn jedoch mehr als ein Zielelement vorhanden ist, werden nach dem ersten für jedes Ziel geklonte Kopien des eingefügten Elements erstellt.

pitx3
quelle
2
Ich denke nicht. Es hört sich so an, als ob das OP nach einer Möglichkeit sucht, den Text zu ändern und keinen neuen Text hinzuzufügen.
Matt Ball
0

Einfache Antwort:

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

Das Problem mit Marks Antwort ist, dass Sie auch leere Textknoten erhalten. Lösung als jQuery-Plugin:

$.fn.textnodes = function () {
    return this.contents().filter(function (i,n) {
        return n.nodeType == 3 && n.textContent.trim() !== "";
    });
};

$("div").textnodes()[0] = "changed text";
br4nnigan
quelle
0

Dies ist eine alte Frage, aber Sie können eine einfache Funktion wie diese erstellen, um Ihr Leben zu erleichtern:

$.fn.toText = function(str) {
    var cache = this.children();
    this.text(str).append(cache);
}

Beispiel:

<div id="my-div">
   **text to change**
   <p>
       text that should not change
   </p>
   <p>
       text that should not change
   </p>
</div>

Verwendung:

$("#my-div").toText("helloworld");
rotaercz
quelle
0

2019 vesrsion - Short & Simple

document.querySelector('#your-div-id').childNodes[0].nodeValue = 'new text';

Erläuterung

document.querySelector('#your-div-id') wird zur Auswahl des übergeordneten Elements verwendet (das Element, dessen Text Sie ändern möchten)

.childNodes[0] wählt den Textknoten aus

.nodeValue = 'new text' setzt den Textknotenwert auf "neuer Text"


Diese Antwort ist möglicherweise von Dean Martins Kommentar inspiriert. Ich kann es nicht mit Sicherheit sagen, da ich diese Lösung seit Jahren verwende. Ich dachte nur, ich sollte diese Wahrscheinlichkeit hier posten, weil sich einige Leute mehr darum kümmern als um die Tatsache, dass dies die beste Lösung ist.

Silber Ringvee
quelle
2
Sie haben gerade den Kommentar von Dean Martin aus dem Jahr 2014 kopiert und behaupten, dies sei Ihre Lösung für 2019. Verwenden Sie auch eine unnötige Kombination aus jQuery und einfachem Javascript, was meiner Meinung nach eine schlechte Praxis für eine gute Lesbarkeit ist. Zuletzt haben Sie keine Details zur Funktionsweise Ihrer Lösung angegeben. Es ist nicht das komplizierteste, aber dieses Problem ist es auch nicht. Daher sind es wahrscheinlich ziemlich neue Programmierer, die dies lesen und eine zusätzliche Erklärung gebrauchen könnten, zum Beispiel, dass Sie den nativen DOM-Knoten vom jQuery-Objekt erhalten, indem Sie auf den Array-Index zugreifen.
Mark Baijens
@ MarkBaijens Ich denke, Sie haben vielleicht Recht, Dean Martins Kommentar könnte sein, woher ich diesen Ausschnitt vor Jahren habe. Wie auch immer, ich benutze es seitdem und habe es im Januar von meinem persönlichen Code-Repo (wo ich nützliche Skripte aufführe) kopiert. Eine detailliertere Erklärung wurde hinzugefügt und unnötige jQuery entfernt.
Silver Ringvee
Dies ist bei weitem die einfachste Lösung, die tatsächlich funktioniert, und die Leute sollten sie verwenden, obwohl Sie kein Lob dafür bekommen, dass Sie sie als Ihre eigene verpfänden, ohne Dean Martin die Ehre zu erweisen. Ich stimme auch Mark Baijens zu, dass die reine Vanilla JS-Implementierung in diesem Fall besser ist als das Verwechseln von jQuery und Vanilla JS. Nicht nur für eine bessere Lesbarkeit, sondern auch für eine bessere Leistung, da jQuery die Dinge verlangsamt.
Miqi180
@ Miqi180 - wie ich bereits oben sagte, ist dies möglich, ich erinnere mich nicht, woher ich diese Lösung zuerst habe. Ich benutze es seit Jahren in meiner Arbeit. In der Antwort wurde eine Notiz hinzugefügt. Hoffentlich hilft es Leuten wie Ihnen, denen die beste Lösung hier auf SO nicht
wichtig ist