ฉันจะเปลี่ยนข้อความขององค์ประกอบโดยไม่เปลี่ยนองค์ประกอบลูกได้อย่างไร


120

ฉันต้องการอัปเดตข้อความขององค์ประกอบแบบไดนามิก:

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

ฉันยังใหม่กับ jQuery ดังนั้นงานนี้ดูเหมือนจะค่อนข้างท้าทายสำหรับฉัน ใครช่วยชี้ฉันไปที่ฟังก์ชัน / ตัวเลือกที่จะใช้?

ถ้าเป็นไปได้ฉันต้องการทำโดยไม่ต้องเพิ่มคอนเทนเนอร์ใหม่สำหรับข้อความที่ฉันต้องการเปลี่ยนแปลง


7
“ ถ้าเป็นไปได้ฉันอยากจะทำโดยไม่ต้องเพิ่มคอนเทนเนอร์ใหม่สำหรับข้อความที่ฉันต้องการเปลี่ยนแปลง” - จริงเหรอ? เพราะมันจะง่ายกว่ามากเมื่อมีคอนเทนเนอร์อยู่ที่นั่น
Paul D. Waite

พวกฉันดูคำถามเดิมและฉันไม่คิดว่า OP จะพูดอะไรเกี่ยวกับองค์ประกอบของเด็ก ...
Šime Vidas

ตามมาตรฐาน W3 div ไม่สามารถมีโหนดข้อความได้ (ถ้าจำไม่ผิด) ควรเพิ่มที่เก็บข้อความเช่น <p>, <h1> ฯลฯ
Mark Baijens

2
@Mark: อาจอยู่ใน (X) HTML Strict แต่ไม่ใช่อีกต่อไป (HTML5 อยู่ที่นี่แล้ว)
Paul D. Waite

@Matt Ball: ใน html จริงมีแท็กช่วงแทน someChild
ika

คำตอบ:


76

Mark มีทางออกที่ดีกว่าเมื่อใช้ jQueryแต่คุณอาจสามารถทำได้ใน JavaScript ปกติด้วย

ใน Javascript childNodesคุณสมบัติจะให้โหนดลูกทั้งหมดขององค์ประกอบรวมถึงโหนดข้อความ

ดังนั้นหากคุณรู้ว่าข้อความที่คุณต้องการเปลี่ยนแปลงมักจะเป็นสิ่งแรกในองค์ประกอบจากนั้นให้เช่น HTML นี้:

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

คุณสามารถทำได้:

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

var text_to_change = your_div.childNodes[0];

text_to_change.nodeValue = 'new text';

แน่นอนคุณยังสามารถใช้ jQuery เพื่อเลือก<div>ในตอนแรก (เช่นvar your_div = $('your_div').get(0);)


1
ไม่จำเป็นต้องแทนที่โหนดข้อความ เพียงแค่เปลี่ยนสิ่งที่มีอยู่dataหรือnodeValueทรัพย์สิน
Tim Down

@ ทิม: อาฉันคิดว่าต้องมีวิธีที่ง่ายกว่านี้ ไม่เคยทำ JavaScript มากก่อนที่ jQuery จะเข้ามา ไชโยฉันจะแก้ไขคำตอบตามนั้น
Paul D.Waite

11
ดังนั้นการปรับใช้คำตอบนี้ให้เป็นปัจจุบันมากขึ้นคือ$('#yourDivId')[0].childNodes[0].nodeValue = 'New Text';
Dean Martin

วิธีแก้ปัญหาที่สั้นและง่ายที่สุด - stackoverflow.com/a/54365288/4769218
Silver Ringvee

1
"คุณอาจทำได้ในจาวาสคริปต์ปกติด้วย"
duhaime

65

อัปเดต 2018

เนื่องจากนี่เป็นคำตอบที่ได้รับความนิยมมากฉันจึงตัดสินใจอัปเดตและตกแต่งมันเล็กน้อยโดยการเพิ่มตัวเลือกโหนดข้อความลงใน jQuery เป็นปลั๊กอิน

ในตัวอย่างด้านล่างคุณจะเห็นว่าฉันกำหนดฟังก์ชัน jQuery ใหม่ที่รับ textNodes ทั้งหมด (และเท่านั้น) คุณสามารถเชื่อมต่อฟังก์ชันนี้ได้เช่นกันกับตัวอย่างเช่นfirst()ฟังก์ชัน ฉันทำการตัดแต่งบนโหนดข้อความและตรวจสอบว่ามันไม่ว่างเปล่าหลังจากการตัดแต่งหรือไม่เนื่องจากช่องว่างแท็บบรรทัดใหม่ ฯลฯ ได้รับการยอมรับว่าเป็นโหนดข้อความ หากคุณต้องการโหนดเหล่านั้นด้วยให้ลบออกจากคำสั่ง if ในฟังก์ชัน jQuery

ฉันได้เพิ่มตัวอย่างวิธีการแทนที่โหนดข้อความแรกและวิธีแทนที่โหนดข้อความทั้งหมด

วิธีนี้ช่วยให้อ่านโค้ดได้ง่ายขึ้นและใช้หลายครั้งได้ง่ายขึ้นและมีวัตถุประสงค์ที่แตกต่างกัน

การอัปเดต 2017 (adrach)ควรใช้งานได้เช่นกันหากคุณต้องการ

เป็นส่วนขยาย jQuery

Javascript (ES) eqivilant


อัปเดต 2017 (adrach):

ดูเหมือนว่ามีหลายอย่างเปลี่ยนไปตั้งแต่โพสต์นี้ นี่คือเวอร์ชันอัปเดต

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

คำตอบเดิม (ใช้ไม่ได้กับเวอร์ชันปัจจุบัน)

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

ที่มา: http://api.jquery.com/contents/


Aha! ฉันรู้ว่ามีฟังก์ชัน jQuery ที่ชาญฉลาดอยู่ที่ไหนสักแห่ง ปัญหาเดียวกับวิธีแก้ปัญหาตามที่คุณเขียนไว้คือทุกโหนดข้อความจะได้รับข้อความถัดไป (เช่นรวมถึงโหนดภายในองค์ประกอบลูก) ฉันเดาว่ามันคงไม่ยากเกินไปที่จะ จำกัด มัน?
Paul D. Waite

10
ฉันมีปัญหาในการใช้.filter(':first')งาน แต่การใช้งาน.first()แทนได้ผลสำหรับฉัน ขอบคุณ!
hollaburoo

16
สิ่งนี้ใช้ไม่ได้กับฉัน.text()(ดูjsfiddle นี้ ) แต่ใช้กับ.replaceWith()( jsfiddle ที่นี่ )
magicalex

2
สิ่งนี้ใช้ได้กับฉันน่าเกลียดเพราะเป็น textObject = $ (myNode) .contents (). filter (function () {return this.nodeType == 3;}) [0] $ (textObject) .replaceWith ("my text" );
Maragues

ใครสงสัยnodeType=3ว่าเป็นตัวกรองค่าเฉลี่ยเฉพาะประเภทโหนดของ "TEXT", w3schools.com/jsref/prop_node_nodetype.aspสำหรับข้อมูลเพิ่มเติม
ktutnik

53

ดูในการดำเนินการ

มาร์กอัป:

$(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
ทางออกที่ดีที่สุดที่ฉันเคยเจอ หรูหราและเรียบง่าย
Yoav Kadosh

3
อย่างไรก็ตามการดำเนินการนี้จะไม่รักษาลำดับของโหนด เช่นถ้าข้อความอยู่ที่ส่วนท้ายขององค์ประกอบก่อนตอนนี้ก็จะเป็นจุดเริ่มต้น
แมตต์

จะไม่รักษาลำดับ แต่ในกรณีส่วนใหญ่คุณต้องการให้ข้อความเป็นโหนดแรกหรือโหนดสุดท้าย ดังนั้นหาก append () ไม่ได้ผลลัพธ์ที่ต้องการให้ลองใส่ไว้ข้างหน้า () หากคุณต้องการให้ลูกที่มีอยู่ด้านหน้าของข้อความ
Sensei

วิธีแก้ปัญหาที่สั้นและง่ายที่สุด - 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");
});

สิ่งนี้เปลี่ยนแปลงเฉพาะโหนดข้อความแรก


9

เพียงแค่ตัดข้อความที่คุณต้องการเปลี่ยนในช่วงที่มีคลาสให้เลือก

ฉันรู้ไม่จำเป็นต้องตอบคำถามของคุณ แต่น่าจะเป็นการฝึกฝนการเขียนโค้ดที่ดีกว่า รักษาความสะอาดและเรียบง่าย

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

Voila!

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

นี่คือทางออกที่ดีที่สุด!
Sleek Geek

5

สำหรับกรณีเฉพาะที่คุณกล่าวถึง:

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

... ง่ายมาก:

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

คุณไม่ได้ระบุว่าคุณต้องการสรุปสิ่งนี้อย่างไร หากคุณต้องการเปลี่ยนข้อความของโหนดข้อความแรกภายในโหนด<div>คุณสามารถทำสิ่งนี้ได้:

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

คำตอบที่ยอดเยี่ยมมากมายที่นี่ แต่จัดการกับโหนดข้อความเดียวกับลูกเท่านั้น ในกรณีของฉันฉันจำเป็นต้องดำเนินการกับโหนดข้อความทั้งหมดและไม่สนใจเด็ก html แต่สงวนการสั่งซื้อ

ดังนั้นหากเรามีกรณีเช่นนี้:

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

เราสามารถใช้รหัสต่อไปนี้เพื่อแก้ไขข้อความเท่านั้นและสงวนการสั่งซื้อ

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

นี่คือjsfiddleของมันที่ใช้งานได้


0

ฉันคิดว่าคุณกำลังมองหา. prependTo ()

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

นอกจากนี้เรายังสามารถเลือกองค์ประกอบบนหน้าและแทรกเข้าไปในองค์ประกอบอื่น:

$ (H2) prependTo ($ ( 'ภาชนะ.')).

หากองค์ประกอบที่เลือกด้วยวิธีนี้ถูกแทรกที่อื่นองค์ประกอบนั้นจะถูกย้ายไปยังเป้าหมาย (ไม่ได้โคลน):

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

อย่างไรก็ตามหากมีองค์ประกอบเป้าหมายมากกว่าหนึ่งองค์ประกอบสำเนาขององค์ประกอบที่แทรกจะถูกสร้างขึ้นสำหรับแต่ละเป้าหมายหลังจากรายการแรก


2
ผมคิดว่าไม่. ดูเหมือนว่า OP กำลังหาวิธีเปลี่ยนข้อความไม่ใช่เพิ่มข้อความใหม่
Matt Ball


0

ปัญหากับคำตอบของ Mark คือคุณได้รับ textnodes ที่ว่างเปล่าเช่นกัน โซลูชันเป็นปลั๊กอิน jQuery:

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

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

0

นี่เป็นคำถามเก่า แต่คุณสามารถสร้างฟังก์ชันง่ายๆเช่นนี้เพื่อทำให้ชีวิตของคุณง่ายขึ้น:

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

ตัวอย่าง:

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

การใช้งาน:

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

0

2019 vesrsion - สั้นและเรียบง่าย

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

คำอธิบาย

document.querySelector('#your-div-id') ใช้สำหรับเลือกพาเรนต์ (องค์ประกอบที่คุณกำลังจะเปลี่ยนข้อความ)

.childNodes[0] เลือกโหนดข้อความ

.nodeValue = 'new text' ตั้งค่าโหนดข้อความเป็น "ข้อความใหม่"


คำตอบนี้อาจได้รับแรงบันดาลใจจากข้อคิดเห็นของ Dean Martin ไม่สามารถพูดได้อย่างแน่นอนเนื่องจากฉันใช้วิธีนี้มาหลายปีแล้ว แค่คิดว่าฉันควรโพสต์ความน่าจะเป็นนี้ไว้ที่นี่เพราะบางคนสนใจมันมากกว่าความจริงที่ว่านี่คือทางออกที่ดีที่สุด


2
คุณเพิ่งคัดลอกความคิดเห็นของ Dean Martin จากปี 2014 และอ้างว่าเป็นโซลูชันปี 2019 ของคุณ นอกจากนี้ยังใช้ jQuery และ Javascript แบบธรรมดาที่ไม่จำเป็นซึ่งในความคิดของฉันเป็นการปฏิบัติที่ไม่ดีสำหรับการอ่านที่ดี ล่าสุดคุณไม่ได้ใส่รายละเอียดเกี่ยวกับวิธีการแก้ปัญหาของคุณ ไม่ใช่เรื่องที่ซับซ้อนที่สุด แต่ก็ไม่ใช่ปัญหานี้ดังนั้นจึงน่าจะเป็นโปรแกรมเมอร์หน้าใหม่ที่อ่านสิ่งนี้ซึ่งสามารถใช้คำอธิบายเพิ่มเติมได้เช่นคุณได้รับโหนด DOM ดั้งเดิมจากวัตถุ jQuery โดยการเข้าถึงดัชนีอาร์เรย์
Mark Baijens

@MarkBaijens ฉันคิดว่าคุณคิดถูกความคิดเห็นของ Dean Martin อาจเป็นที่ที่ฉันได้รับตัวอย่างนี้เมื่อหลายปีก่อน อย่างไรก็ตามฉันใช้มันมาตลอดและเพิ่งคัดลอกจาก repo รหัสส่วนตัวของฉัน (ซึ่งฉันแสดงรายการสคริปต์ที่มีประโยชน์) ในเดือนมกราคม เพิ่มคำอธิบายโดยละเอียดและลบ jQuery ที่ไม่จำเป็นออก
Silver Ringvee

นี่เป็นวิธีแก้ปัญหาที่ง่ายที่สุดที่ใช้งานได้จริงและผู้คนควรใช้แม้ว่าคุณจะไม่ได้รับความชื่นชอบใด ๆ จากการอวดอ้างเป็นของคุณเองโดยไม่ให้เครดิตกับ Dean Martin ฉันยังเห็นด้วยกับ Mark Baijens ว่าการใช้ Vanilla JS แบบบริสุทธิ์ในกรณีนี้ดีกว่าการผสม jQuery และ Vanilla JS ไม่เพียง แต่เพื่อการอ่านที่ดีขึ้น แต่ยังเพิ่มประสิทธิภาพการทำงานด้วยเนื่องจาก jQuery ทำให้สิ่งต่างๆช้าลง
Miqi180

@ Miqi180 - ตามที่ได้กล่าวไปแล้วข้างต้นเป็นไปได้ฉันจำไม่ได้ว่าฉันหาวิธีแก้ปัญหานี้มาจากไหน ฉันใช้มันในการทำงานของฉันมาหลายปีแล้ว เพิ่มหมายเหตุในคำตอบ หวังว่าจะช่วยให้คนอย่างคุณที่ไม่สนใจวิธีแก้ปัญหาที่ดีที่สุดที่ SO:
Silver Ringvee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.