Làm cách nào để thay đổi văn bản của một phần tử mà không thay đổi các phần tử con của nó?


120

Tôi muốn cập nhật động văn bản của phần tử:

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

Tôi mới sử dụng jQuery, vì vậy nhiệm vụ này có vẻ khá khó khăn đối với tôi. Ai đó có thể chỉ cho tôi một chức năng / bộ chọn để sử dụng không?

Nếu có thể, tôi muốn làm điều đó mà không cần thêm vùng chứa mới cho văn bản tôi cần thay đổi.


7
“Nếu có thể, tôi muốn làm điều đó mà không cần thêm vùng chứa mới cho văn bản mà tôi cần thay đổi.” - có thật không? Bởi vì nó sẽ dễ dàng hơn nhiều với một thùng chứa trong đó.
Paul D. Waite

Guys, tôi nhìn vào câu hỏi ban đầu và tôi không nghĩ rằng OP nói bất cứ điều gì về yếu tố con ...
Šime Vidas

Theo tiêu chuẩn W3, div thậm chí không thể có các nút văn bản (nếu tôi nhớ chính xác). Một vùng chứa văn bản như <p>, <h1>, v.v. nên được thêm vào.
Mark Baijens

2
@Mark: có thể ở (X) HTML Nghiêm ngặt, nhưng không phải nữa. (HTML5 hiện có ở đây.)
Paul D. Waite

@Matt Ball: Trong html thực tế có các thẻ span thay vì someChild.
ika

Câu trả lời:


75

Mark's có một giải pháp tốt hơn bằng cách sử dụng jQuery , nhưng bạn cũng có thể làm điều này trong JavaScript thông thường.

Trong Javascript, thuộc childNodestính cung cấp cho bạn tất cả các nút con của một phần tử, bao gồm cả các nút văn bản.

Vì vậy, nếu bạn biết văn bản bạn muốn thay đổi luôn là thứ đầu tiên trong phần tử, thì hãy cho ví dụ như HTML này:

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

Bạn có thể làm điều này:

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

var text_to_change = your_div.childNodes[0];

text_to_change.nodeValue = 'new text';

Tất nhiên, bạn vẫn có thể sử dụng jQuery để chọn <div>ở vị trí đầu tiên (tức là var your_div = $('your_div').get(0);).


1
Không cần thay thế nút văn bản. Chỉ cần thay đổi một người datahoặc nodeValuetài sản hiện có.
Tim Down

@Tim: à, tôi nghĩ phải có một cách dễ dàng hơn. Chưa bao giờ làm nhiều JavaScript trước khi jQuery xuất hiện. Chúc mừng, tôi sẽ chỉnh sửa câu trả lời cho phù hợp.
Paul D. Waite

11
Vì vậy, một cách triển khai cập nhật hơn cho câu trả lời này sẽ là$('#yourDivId')[0].childNodes[0].nodeValue = 'New Text';
Dean Martin

Cho đến nay các giải pháp ngắn nhất và đơn giản nhất - stackoverflow.com/a/54365288/4769218
Bạc Ringvee

1
"Bạn có thể có thể làm điều này trong javascript thường xuyên quá"
duhaime

65

Cập nhật 2018

Vì đây là một câu trả lời khá phổ biến nên tôi quyết định cập nhật và làm đẹp nó một chút bằng cách thêm công cụ chọn textnode vào jQuery làm plugin.

Trong đoạn mã bên dưới, bạn có thể thấy rằng tôi xác định một hàm jQuery mới nhận tất cả (và chỉ) các textNodes. Bạn cũng có thể xâu chuỗi hàm này với ví dụ như first()hàm. Tôi thực hiện cắt trên nút văn bản và kiểm tra xem nó có trống không sau khi cắt vì dấu cách, tab, dòng mới, v.v. cũng được nhận dạng là nút văn bản. Nếu bạn cũng cần những nút đó thì chỉ cần xóa nó khỏi câu lệnh if trong hàm jQuery.

Tôi đã thêm một ví dụ về cách thay thế nút văn bản đầu tiên và cách thay thế tất cả các nút văn bản.

Cách tiếp cận này giúp bạn đọc mã dễ dàng hơn và dễ dàng sử dụng nó nhiều lần với các mục đích khác nhau.

Bản cập nhật 2017 (adrach) vẫn sẽ hoạt động tốt nếu bạn thích điều đó.

Dưới dạng phần mở rộng jQuery

Javascript (ES) eqivilant


Cập nhật 2017 (adrach):

Có vẻ như một số thứ đã thay đổi kể từ khi điều này được đăng. Đây là một phiên bản cập nhật

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

Câu trả lời gốc (Không hoạt động cho các phiên bản hiện tại)

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

Nguồn: http://api.jquery.com/contents/


Aha! Tôi biết sẽ có một hàm jQuery thông minh ở đâu đó. Chỉ có một vấn đề với giải pháp như bạn đã viết là mọi nút văn bản nhận được văn bản tiếp theo (ví dụ bao gồm những cái bên trong các phần tử con). Tôi đoán sẽ không quá khó để hạn chế nó?
Paul D. Waite

10
Tôi đã gặp một số khó khăn khi sử dụng .filter(':first'), nhưng việc sử dụng .first()thay thế đã hiệu quả với tôi. Cảm ơn!
hollaburoo

16
Điều này không hiệu quả với tôi với .text()(xem jsfiddle này ) nhưng lại làm với .replaceWith()( jsfiddle tại đây ).
magicalex

2
Điều này phù hợp với tôi, xấu vì nó là textObject = $ (myNode) .contents (). Filter (function () {return this.nodeType == 3;}) [0] $ (textObject) .replaceWith ("văn bản của tôi" );
Maragues

bất kỳ ai tò mò về nodeType=3nó có nghĩa là loại nút chỉ lọc của "TEXT", w3schools.com/jsref/prop_node_nodetype.asp để biết thêm thông tin
ktutnik

53

Xem trong hành động

Đánh dấu:

$(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
Cho đến nay, giải pháp tốt nhất mà tôi đã xem qua. Thanh lịch và đơn giản.
Yoav Kadosh

3
Tuy nhiên, điều này sẽ không bảo toàn thứ tự của các nút. Ví dụ: nếu văn bản ở cuối phần tử trước, thì bây giờ nó sẽ ở đầu.
Matt,

Nó sẽ không bảo toàn thứ tự nhưng trong hầu hết các trường hợp, bạn muốn văn bản là nút đầu tiên hoặc nút cuối cùng. Vì vậy, nếu append () không nhận được kết quả mong muốn, hãy thử prepend () nếu bạn muốn các phần tử con hiện có ở trước văn bản.
Sensei

Cho đến nay các giải pháp ngắn nhất và đơn giản nhất - stackoverflow.com/a/54365288/4769218
Bạc 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");
});

Điều này chỉ thay đổi textnode đầu tiên


9

Chỉ cần bọc văn bản bạn muốn thay đổi trong một khoảng với một lớp để chọn.

Không nhất thiết phải trả lời câu hỏi của bạn mà tôi biết, nhưng, có lẽ là một phương pháp viết mã tốt hơn. Giữ mọi thứ sạch sẽ và đơn giản

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

Đây là giải pháp tốt nhất!
Sleek Geek

5

Đối với trường hợp cụ thể bạn đã đề cập:

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

... nó rất là dễ:

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

Bạn không nói rõ bạn muốn khái quát điều này như thế nào. Giả sử, nếu bạn muốn thay đổi văn bản của nút văn bản đầu tiên trong <div>, bạn có thể làm như sau:

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

Đây là chưa một phương pháp khác: 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

Rất nhiều câu trả lời tuyệt vời ở đây nhưng chúng chỉ xử lý một nút văn bản với trẻ em. Trong trường hợp của tôi, tôi cần thao tác trên tất cả các nút văn bản và bỏ qua các nút con html NHƯNG BẢO QUẢN LỆNH.

Vì vậy, nếu chúng ta gặp trường hợp như thế này:

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

Chúng tôi có thể sử dụng mã sau để chỉ sửa đổi văn bản VÀ BẢO QUẢN ĐƠN HÀNG

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

Đây là jsfiddle của nó hoạt động


0

Tôi nghĩ bạn đang tìm kiếm .prependTo ().

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

Chúng tôi cũng có thể chọn một phần tử trên trang và chèn nó vào một phần tử khác:

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

Nếu một phần tử được chọn theo cách này được chèn vào nơi khác, nó sẽ được chuyển vào đích (không được sao chép):

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

Tuy nhiên, nếu có nhiều hơn một phần tử đích, các bản sao nhân bản của phần tử được chèn vào sẽ được tạo cho mỗi mục tiêu sau phần tử đầu tiên.


2
Tôi nghĩ là không. Có vẻ như OP đang tìm cách thay đổi văn bản chứ không phải thêm văn bản mới.
Matt Ball vào

0

Câu trả lời đơn giản:

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

0

Vấn đề với câu trả lời của Mark là bạn cũng nhận được các textnodes trống. Giải pháp dưới dạng 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

Đây là một câu hỏi cũ nhưng bạn có thể tạo một hàm đơn giản như sau để làm cho cuộc sống của bạn dễ dàng hơn:

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

Thí dụ:

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

Sử dụng:

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

0

2019 vesrsion - Ngắn và Đơn giản

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

Giải trình

document.querySelector('#your-div-id') được sử dụng để chọn phần tử gốc (phần tử mà văn bản bạn sắp thay đổi)

.childNodes[0] chọn nút văn bản

.nodeValue = 'new text' đặt giá trị nút văn bản thành "văn bản mới"


Câu trả lời này có thể được lấy cảm hứng từ nhận xét của Dean Martin. Không thể nói chắc chắn vì tôi đã sử dụng giải pháp này trong nhiều năm rồi. Tôi chỉ nghĩ rằng tôi nên đăng xác suất này ở đây vì một số người quan tâm đến nó nhiều hơn thực tế rằng đây là giải pháp tốt nhất.


2
Bạn vừa sao chép nhận xét của Dean Martin từ năm 2014 và khẳng định đây là giải pháp năm 2019 của bạn. Ngoài ra, hãy sử dụng sự kết hợp không cần thiết giữa jQuery và Javascript đơn giản, theo tôi là một phương pháp không tốt để dễ đọc. Lần cuối cùng bạn không đưa ra bất kỳ chi tiết nào về cách giải pháp của bạn hoạt động. Đây không phải là vấn đề phức tạp nhất nhưng cũng không phải là vấn đề này vì vậy có lẽ những lập trình viên khá mới đọc điều này có thể sử dụng một số giải thích bổ sung, chẳng hạn như bạn lấy nút DOM gốc từ đối tượng jQuery bằng cách truy cập vào chỉ mục mảng.
Mark Baijens

@MarkBaijens Tôi nghĩ bạn có thể đúng, nhận xét của Dean Martin có thể là nơi tôi lấy đoạn này nhiều năm trước. Dù sao, tôi đã sử dụng nó kể từ đó và chỉ sao chép nó từ kho mã cá nhân của tôi (nơi tôi liệt kê các tập lệnh hữu ích) vào tháng Giêng. Đã thêm giải thích chi tiết hơn và loại bỏ jQuery không cần thiết.
Silver Ringvee

Cho đến nay, đây là giải pháp đơn giản nhất thực sự hiệu quả và mọi người nên sử dụng nó, mặc dù bạn không nhận được bất kỳ kudo nào khi cầm cố nó như của riêng bạn mà không ghi công cho Dean Martin. Tôi cũng đồng ý với Mark Baijens rằng việc triển khai Vanilla JS thuần túy trong trường hợp này tốt hơn là trộn jQuery và Vanilla JS. Không chỉ để dễ đọc hơn mà còn cho hiệu suất tốt hơn khi jQuery làm chậm mọi thứ.
Miqi180

@ Miqi180 - như tôi đã nói ở trên, điều này có thể xảy ra, tôi không nhớ nơi đầu tiên tôi có giải pháp này. Tôi đã sử dụng nó trong công việc của mình nhiều năm nay. Đã thêm ghi chú trong câu trả lời. Hy vọng rằng nó sẽ giúp những người như bạn, những người không quan tâm đến giải pháp tốt nhất ở đây trên SO:
Bạc Ringvee
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.