Bagaimana cara mengubah teks elemen tanpa mengubah elemen anaknya?

120

Saya ingin memperbarui teks elemen secara dinamis:

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

Saya baru mengenal jQuery, jadi tugas ini tampaknya cukup menantang bagi saya. Bisakah seseorang mengarahkan saya ke fungsi / pemilih untuk digunakan?

Jika memungkinkan, saya ingin melakukannya tanpa menambahkan wadah baru untuk teks yang perlu saya ubah.

ika
sumber
7
“Jika memungkinkan, saya ingin melakukannya tanpa menambahkan wadah baru untuk teks yang perlu saya ubah.” - Betulkah? Karena akan lebih mudah dengan adanya wadah di sana.
Paul D. Waite
Teman-teman, saya melihat pertanyaan awal dan saya tidak berpikir bahwa OP mengatakan apa-apa tentang elemen anak ...
Šime Vidas
Menurut standar W3 div bahkan tidak dapat memiliki node teks (jika saya ingat benar). Wadah teks seperti <p>, <h1>, dll harus ditambahkan.
Mark Baijens
2
@Mark: mungkin dalam (X) HTML Strict, tetapi tidak lagi. (HTML5 ada di sini sekarang.)
Paul D. Waite
@Matt Ball: Dalam html sebenarnya ada tag span, bukan someChild.
ika

Jawaban:

75

Mark mendapatkan solusi yang lebih baik menggunakan jQuery , tetapi Anda mungkin juga dapat melakukan ini di JavaScript biasa.

Dalam Javascript, childNodesproperti memberi Anda semua node turunan dari suatu elemen, termasuk node teks.

Jadi, jika Anda tahu teks yang ingin Anda ubah selalu menjadi hal pertama dalam elemen, lalu berikan contoh HTML ini:

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

Anda bisa melakukan ini:

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

var text_to_change = your_div.childNodes[0];

text_to_change.nodeValue = 'new text';

Tentu saja, Anda masih dapat menggunakan jQuery untuk memilih <div>di tempat pertama (yaitu var your_div = $('your_div').get(0);).

Paul D. Waite
sumber
1
Tidak perlu mengganti node teks. Ubah saja yang sudah ada dataatau nodeValueproperti.
Tim Down
@ Tim: ah, saya pikir pasti ada cara yang lebih mudah. Tidak pernah melakukan banyak JavaScript sebelum jQuery muncul. Cheers, saya akan mengedit jawabannya.
Paul D. Waite
11
Jadi implementasi yang lebih mutakhir dari jawaban ini adalah$('#yourDivId')[0].childNodes[0].nodeValue = 'New Text';
Dean Martin
Sejauh ini solusi terpendek dan paling sederhana - stackoverflow.com/a/54365288/4769218
Silver Ringvee
1
"Anda mungkin juga dapat melakukan ini dalam javascript biasa"
duhaime
65

Perbarui 2018

Karena ini adalah jawaban yang cukup populer, saya memutuskan untuk memperbarui dan mempercantiknya sedikit dengan menambahkan pemilih textnode ke jQuery sebagai plugin.

Dalam potongan di bawah ini Anda dapat melihat bahwa saya mendefinisikan fungsi jQuery baru yang mendapatkan semua (dan hanya) textNodes. Anda dapat menghubungkan first()fungsi ini juga dengan misalnya fungsi tersebut. Saya melakukan trim pada node teks dan memeriksa apakah tidak kosong setelah trim karena spasi, tab, baris baru, dll. Juga dikenali sebagai node teks. Jika Anda membutuhkan node itu juga, cukup hapus itu dari pernyataan if di fungsi jQuery.

Saya menambahkan contoh bagaimana mengganti simpul teks pertama dan bagaimana mengganti semua simpul teks.

Pendekatan ini membuatnya lebih mudah untuk membaca kode dan lebih mudah untuk digunakan berkali-kali dan dengan tujuan yang berbeda.

The Perbarui 2017 (adrach) harus tetap bekerja dengan baik jika Anda lebih suka itu.

Sebagai ekstensi jQuery

Eqivilant Javascript (ES)


Perbarui 2017 (adrach):

Sepertinya ada beberapa hal yang berubah sejak ini diposting. Ini adalah versi yang diperbarui

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

Jawaban asli (Tidak berfungsi untuk versi saat ini)

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

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

Mark Baijens
sumber
Aha! Saya tahu akan ada fungsi jQuery yang pintar di suatu tempat. Satu-satunya masalah dengan solusi seperti yang Anda tulis adalah bahwa setiap node teks mendapatkan teks berikutnya (misalnya termasuk yang ada di dalam elemen anak). Saya kira tidak akan terlalu sulit untuk membatasinya?
Paul D. Waite
10
Saya mengalami beberapa masalah saat menggunakan .filter(':first'), tetapi menggunakan .first()malah berhasil untuk saya. Terima kasih!
hollaburoo
16
Ini tidak bekerja untuk saya dengan .text()(lihat jsfiddle ini ) tetapi dengan .replaceWith()( jsfiddle di sini ).
magicalex
2
Ini bekerja untuk saya, jelek karena textObject = $ (myNode) .contents (). Filter (function () {return this.nodeType == 3;}) [0] $ (textObject) .replaceWith ("my text" );
Maragues
siapa pun yang ingin tahu tentang nodeType=3itu berarti filter hanya jenis node "TEXT", w3schools.com/jsref/prop_node_nodetype.asp untuk info lebih lanjut
ktutnik
53

Lihat Beraksi

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


sumber
6
Sejauh ini solusi terbaik yang pernah saya temukan. Elegan dan sederhana.
Yoav Kadosh
3
Namun, ini tidak akan mempertahankan urutan node. misalnya jika teks berada di akhir elemen dulu, sekarang akan di awal.
Matt
Ini tidak akan mempertahankan urutan tetapi dalam banyak kasus Anda menginginkan teks sebagai node pertama atau terakhir. Jadi jika append () tidak mendapatkan hasil yang diinginkan, coba prepend () jika Anda ingin turunan yang ada di depan teks.
Sensei
Sejauh ini solusi terpendek dan paling sederhana - stackoverflow.com/a/54365288/4769218
Silver 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");
});

Ini hanya mengubah textnode pertama

ilkin
sumber
9

Cukup bungkus teks yang ingin Anda ubah dalam suatu rentang dengan kelas untuk dipilih.

Belum tentu menjawab pertanyaan Anda, saya tahu, tapi, mungkin praktik pengkodean yang lebih baik. Jaga semuanya tetap bersih dan sederhana

<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
sumber
Ini solusi terbaik!
Sleek Geek
5

Untuk kasus spesifik yang Anda sebutkan:

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

... ini sangat mudah:

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

Anda tidak menyatakan bagaimana Anda ingin menggeneralisasikan ini. Jika, katakanlah, Anda ingin mengubah teks dari simpul teks pertama di dalam <div>, Anda dapat melakukan sesuatu seperti ini:

var child = div.firstChild;
while (child) {
    if (child.nodeType == 3) {
        child.data = "New text";
        break;
    }
    child = child.nextSibling;
}
Tim Down
sumber
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
sumber
1

Berikut adalah belum metode lain: 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
sumber
1

Banyak jawaban bagus di sini tetapi mereka hanya menangani satu simpul teks dengan anak-anak. Dalam kasus saya, saya perlu mengoperasikan semua node teks dan mengabaikan anak html TAPI MELESTARIKAN PEMESANAN.

Jadi jika kita memiliki kasus seperti ini:

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

Kita dapat menggunakan kode berikut untuk memodifikasi teks saja DAN MELESTARIKAN PEMESANAN

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

Berikut adalah jsfiddle itu bekerja

pengguna1254723
sumber
0

Saya pikir Anda sedang mencari .prependTo ().

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

Kami juga dapat memilih elemen di halaman dan memasukkannya ke yang lain:

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

Jika elemen yang dipilih dengan cara ini disisipkan di tempat lain, itu akan dipindahkan ke target (tidak digandakan):

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

Namun, jika ada lebih dari satu elemen target, salinan kloning dari elemen yang disisipkan akan dibuat untuk setiap target setelah yang pertama.

pitx3
sumber
2
Saya pikir tidak. Sepertinya OP mencari cara untuk mengubah teks, bukan menambahkan teks baru.
Matt Ball
0

Jawaban sederhana:

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

Masalah dengan jawaban Mark adalah Anda mendapatkan textnode kosong juga. Solusi sebagai plugin jQuery:

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

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

Ini adalah pertanyaan lama tetapi Anda dapat membuat fungsi sederhana seperti ini untuk membuat hidup Anda lebih mudah:

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

Contoh:

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

Pemakaian:

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

Vesrsion 2019 - Pendek & Sederhana

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

Penjelasan

document.querySelector('#your-div-id') digunakan untuk memilih induk (elemen teks yang akan Anda ubah)

.childNodes[0] memilih node teks

.nodeValue = 'new text' setel nilai simpul teks ke "teks baru"


Jawaban ini mungkin terinspirasi dari komentar Dean Martin. Tidak dapat mengatakan dengan pasti karena saya telah menggunakan solusi ini selama bertahun-tahun sekarang. Hanya berpikir saya harus memposting probabilitas ini di sini karena beberapa orang lebih memedulikannya daripada fakta bahwa ini adalah solusi terbaik.

Silver Ringvee
sumber
2
Anda baru saja menyalin komentar Dean Martin dari 2014 dan mengklaim ini sebagai solusi 2019 Anda. Juga gunakan kombinasi jQuery dan Javascript biasa yang tidak perlu yang menurut saya adalah praktik yang buruk untuk keterbacaan yang baik. Terakhir, Anda tidak mencantumkan detail apa pun tentang cara kerja solusi Anda. Ini bukan yang paling rumit tetapi juga bukan masalah ini sehingga mungkin pemrogram cukup baru yang membaca ini yang dapat menggunakan beberapa penjelasan tambahan misalnya Anda mendapatkan simpul DOM asli dari objek jQuery dengan mengakses indeks array.
Mark Baijens
@MarkBaijens Saya pikir Anda mungkin benar, komentar Dean Martin mungkin berada di tempat saya mendapat potongan ini bertahun-tahun yang lalu. Bagaimanapun, saya telah menggunakannya sejak itu dan baru saja menyalinnya dari repo kode pribadi saya (tempat saya mencantumkan skrip yang berguna) pada bulan Januari. Menambahkan penjelasan yang lebih detail dan menghapus jQuery yang tidak perlu.
Silver Ringvee
Sejauh ini, ini adalah solusi paling sederhana yang benar-benar berfungsi dan orang harus menggunakannya, meskipun Anda tidak mendapatkan pujian untuk menggadaikannya sebagai milik Anda sendiri tanpa memberikan penghargaan kepada Dean Martin. Saya juga setuju dengan Mark Baijens bahwa implementasi Vanilla JS murni dalam hal ini lebih baik daripada mencampur jQuery dan Vanilla JS. Tidak hanya untuk keterbacaan yang lebih baik, tetapi juga untuk kinerja yang lebih baik karena jQuery memperlambat segalanya.
Miqi180
@ Miqi180 - seperti yang sudah saya katakan di atas, ini mungkin, saya tidak ingat di mana saya pertama kali mendapatkan solusi ini. Saya telah menggunakannya dalam pekerjaan saya selama bertahun-tahun sekarang. Menambahkan catatan dalam jawaban. Mudah-mudahan, ini membantu orang-orang seperti Anda yang tidak peduli dengan solusi terbaik di sini di SO:
Silver Ringvee