Come posso modificare il testo di un elemento senza modificare i suoi elementi figlio?


120

Vorrei aggiornare dinamicamente il testo dell'elemento:

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

Sono nuovo in jQuery, quindi questo compito sembra essere piuttosto impegnativo per me. Qualcuno potrebbe indicarmi una funzione / selettore da utilizzare?

Se possibile, mi piacerebbe farlo senza aggiungere un nuovo contenitore per il testo che devo modificare.


7
"Se è possibile, vorrei farlo senza aggiungere un nuovo contenitore per il testo che devo modificare." - veramente? Perché sarebbe molto più facile con un contenitore lì dentro.
Paul D. Waite,

Ragazzi, ho guardato la domanda originale e non credo che l'OP abbia detto nulla sugli elementi figlio ...
Šime Vidas

Secondo gli standard W3 div non può nemmeno avere nodi di testo (se ricordo bene). Dovrebbe essere aggiunto un contenitore di testo come <p>, <h1>, ecc.
Mark Baijens

2
@Mark: forse in (X) HTML Strict, ma non più. (HTML5 è qui ora.)
Paul D. Waite,

@ Matt Ball: Nell'html effettivo ci sono tag span invece di someChild.
ika

Risposte:


75

Mark ha una soluzione migliore usando jQuery , ma potresti essere in grado di farlo anche in JavaScript normale.

In Javascript, la childNodesproprietà fornisce tutti i nodi figli di un elemento, inclusi i nodi di testo.

Quindi, se sapevi che il testo che desideri modificare sarebbe stato sempre la prima cosa nell'elemento, quindi dato ad esempio questo HTML:

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

Potresti farlo:

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

var text_to_change = your_div.childNodes[0];

text_to_change.nodeValue = 'new text';

Ovviamente, puoi ancora usare jQuery per selezionare il <div>in primo luogo (cioè var your_div = $('your_div').get(0);).


1
Non è necessario sostituire il nodo di testo. Basta cambiare quello esistente datao la nodeValueproprietà.
Tim Down

@ Tim: ah, pensavo ci dovesse essere un modo più semplice. Non ho mai fatto molto JavaScript prima che arrivasse jQuery. Saluti, modifico la risposta di conseguenza.
Paul D. Waite,

11
Quindi un'implementazione più aggiornata di questa risposta sarebbe$('#yourDivId')[0].childNodes[0].nodeValue = 'New Text';
Dean Martin

Di gran lunga la soluzione più breve e più semplice - stackoverflow.com/a/54365288/4769218
Argento Ringvee

1
"Potresti essere in grado di farlo anche in javascript normale"
duhaime

65

Aggiornamento 2018

Poiché questa è una risposta piuttosto popolare, ho deciso di aggiornarla e abbellirla un po 'aggiungendo il selettore textnode a jQuery come plugin.

Nello snippet qui sotto puoi vedere che definisco una nuova funzione jQuery che ottiene tutti (e solo) i textNodes. È possibile concatenare questa funzione anche con, ad esempio, la first()funzione. Faccio un taglio sul nodo di testo e controllo se non è vuoto dopo il taglio perché anche spazi, tabulazioni, nuove linee, ecc. Sono riconosciuti come nodi di testo. Se hai bisogno anche di quei nodi, rimuovilo semplicemente dall'istruzione if nella funzione jQuery.

Ho aggiunto un esempio su come sostituire il primo nodo di testo e su come sostituire tutti i nodi di testo.

Questo approccio rende più facile leggere il codice e più facile utilizzarlo più volte e con scopi diversi.

L' aggiornamento 2017 (adrach) dovrebbe comunque funzionare anche se lo preferisci.

Come estensione jQuery

Eqivilant Javascript (ES)


Aggiornamento 2017 (adrach):

Sembra che diverse cose siano cambiate da quando è stato pubblicato. Ecco una versione aggiornata

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

Risposta originale (non funziona per le versioni attuali)

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

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


Aha! Sapevo che da qualche parte ci sarebbe stata una funzione jQuery intelligente. L'unico problema con la soluzione come l'hai scritta è che ogni nodo di testo riceve il testo successivo (ad esempio, includendo quelli all'interno degli elementi figli). Immagino che non sarebbe troppo difficile limitarlo però?
Paul D. Waite

10
Ho avuto qualche problema con l'utilizzo .filter(':first'), ma l'utilizzo .first()invece ha funzionato per me. Grazie!
hollaburoo

16
Questo non funziona per me con .text()(vedi questo jsfiddle ) ma funziona con .replaceWith()( jsfiddle qui ).
magicalex

2
Questo funziona per me, brutto perché è textObject = $ (myNode) .contents (). Filter (function () {return this.nodeType == 3;}) [0] $ (textObject) .replaceWith ("my text" );
Maragues

chiunque sia curioso di sapere nodeType=3è filtrare solo il tipo di nodo "TEXT", w3schools.com/jsref/prop_node_nodetype.asp per maggiori informazioni
ktutnik

53

Guarda in azione

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" />


6
Di gran lunga la migliore soluzione che abbia mai incontrato. Elegante e semplice.
Yoav Kadosh

3
Tuttavia, ciò non manterrà l'ordine dei nodi. Ad esempio, se il testo fosse prima alla fine dell'elemento, ora sarebbe all'inizio.
Matt

Non manterrà l'ordine ma nella maggior parte dei casi si desidera che il testo sia il primo o l'ultimo nodo. Quindi se append () non ottiene il risultato desiderato, prova a prepend () se vuoi che i figli esistenti siano davanti al testo.
Sensei

Di gran lunga la soluzione più breve e più semplice - stackoverflow.com/a/54365288/4769218
Argento Ringvee

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");
});

Questo cambia solo il primo textnode


9

Racchiudi semplicemente il testo che desideri modificare in un intervallo con una classe da selezionare.

Non risponde necessariamente alla tua domanda, lo so, ma probabilmente una migliore pratica di codifica. Mantieni le cose pulite e semplici

<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>

Ecco!

$('#header .mytext').text('New text here')

Questa è la soluzione migliore!
Sleek Geek

5

Per il caso specifico che hai citato:

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

... questo è molto semplice:

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

Non dici come vuoi generalizzare questo. Se, diciamo, vuoi cambiare il testo del primo nodo di testo all'interno di <div>, potresti fare qualcosa del genere:

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

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>


1

Ecco ancora un altro metodo: 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);

1

Molte ottime risposte qui, ma gestiscono solo un nodo di testo con i bambini. Nel mio caso dovevo operare su tutti i nodi di testo e ignorare i figli html MA PRESERVARE L'ORDINE.

Quindi, se abbiamo un caso come questo:

<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>

Possiamo usare il seguente codice per modificare solo il testo E PRESERVARE L'ORDINE

    $('#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>

Ecco il jsfiddle del suo funzionamento


0

Penso che tu stia cercando .prependTo ().

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

Possiamo anche selezionare un elemento nella pagina e inserirlo in un altro:

$ ( 'H2') prependTo ($ ( 'contenitore.')).;

Se un elemento selezionato in questo modo viene inserito altrove, verrà spostato nella destinazione (non clonato):

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

Se è presente più di un elemento target, tuttavia, verranno create copie clonate dell'elemento inserito per ciascun target dopo il primo.


2
Penso di no. Sembra che l'OP stia cercando un modo per modificare il testo, non aggiungere nuovo testo.
Matt Ball

0

Risposta semplice:

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

0

Il problema con la risposta di Mark è che ottieni anche textnodes vuoti. Soluzione come plugin jQuery:

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

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

0

Questa è una vecchia domanda, ma puoi creare una semplice funzione come questa per semplificarti la vita:

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

Esempio:

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

Uso:

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

0

Versione 2019 - Breve e semplice

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

Spiegazione

document.querySelector('#your-div-id') viene utilizzato per selezionare il genitore (l'elemento di cui si sta per modificare il testo)

.childNodes[0] seleziona il nodo di testo

.nodeValue = 'new text' imposta il valore del nodo di testo su "nuovo testo"


Questa risposta è forse ispirata dal commento di Dean Martin. Non posso dirlo con certezza dato che utilizzo questa soluzione da anni ormai. Ho solo pensato di pubblicare questa probabilità qui perché ad alcune persone interessa più del fatto che questa è la soluzione migliore.


2
Hai appena copiato il commento di Dean Martin del 2014 e lo dichiari come la tua soluzione per il 2019. Usa anche una combinazione non necessaria di jQuery e semplice Javascript che a mio parere è una cattiva pratica per una buona leggibilità. Per ultimo non hai inserito alcun dettaglio su come funziona la tua soluzione. Non è il più complicato, ma non lo è nemmeno questo problema, quindi probabilmente sono i programmatori abbastanza nuovi che leggono questo che potrebbero usare qualche spiegazione extra, ad esempio che ottieni il nodo DOM nativo dall'oggetto jQuery accedendo all'indice dell'array.
Mark Baijens

@MarkBaijens Penso che potresti avere ragione, il commento di Dean Martin potrebbe essere il punto in cui ho ottenuto questo frammento anni fa. Ad ogni modo, l'ho usato da allora e l'ho appena copiato dal mio repository di codice personale (dove elenco script utili) a gennaio. Aggiunta una spiegazione più dettagliata e rimosso jQuery non necessario.
Silver Ringvee

Questa è di gran lunga la soluzione più semplice che funziona davvero e le persone dovrebbero usarla, anche se non ottieni alcun complimento per averla impegnata come tua senza dare credito a Dean Martin. Sono anche d'accordo con Mark Baijens sul fatto che l'implementazione pura di Vanilla JS in questo caso è meglio che mescolare jQuery e Vanilla JS. Non solo per una migliore leggibilità, ma anche per prestazioni migliori poiché jQuery rallenta le cose.
Miqi180

@ Miqi180 - come ho già detto sopra, questo è possibile, non ricordo dove ho preso questa soluzione per la prima volta. Lo uso nel mio lavoro da anni ormai. Aggiunta una nota nella risposta. Si spera che aiuti le persone come te che non si preoccupano della soluzione migliore qui su SO:
Silver Ringvee
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.