Як я можу змінити текст елемента, не змінюючи його дочірніх елементів?


120

Я хотів би динамічно оновити текст елемента:

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

Я новачок у jQuery, тому це завдання здається для мене досить складним. Чи може хтось вказати мені на функцію / селектор, який слід використовувати?

Якщо це можливо, я хотів би зробити це без додавання нового контейнера для тексту, який мені потрібно змінити.


7
"Якщо це можливо, я хотів би зробити це без додавання нового контейнера для тексту, який мені потрібно змінити." - справді? Тому що з контейнером там буде набагато простіше.
— Пол Д. Уейт

Хлопці, я подивився на оригінальне запитання і не думаю, що ОП нічого не сказала про дитячі елементи ...
— Šime Vidas

Відповідно до стандартів W3 div навіть не може мати текстові вузли (якщо я пам'ятаю правильно). Необхідно додати текстовий контейнер типу <p>, <h1> тощо.
— Марк Байєнс

2
@Mark: можливо в (X) HTML Strict, але не більше. (HTML5 зараз тут.)
— Пол Д. Уайт

@Matt Ball: Насправді html є теги span замість someChild.
— ika

Відповіді:


75

Марк отримав краще рішення за допомогою 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: ах, я думав, що повинен бути простіший спосіб. Ніколи не робив багато JavaScript, перш ніж з'явився jQuery. Привіт, відповідь я відредагую відповідно.
— Пол Д. Уейт

11
Тож більш актуальною є реалізація цієї відповіді$('#yourDivId')[0].childNodes[0].nodeValue = 'New Text';
— Дін Мартін

До сих пір найкоротший і просте рішення - stackoverflow.com/a/54365288/4769218
— Silver Ringvee

1
"Ви можете зробити це також у звичайному javascript"
— duhaime

65

Оновлення 2018 року

Оскільки це досить популярна відповідь, я вирішив її трохи оновити та прикрасити, додавши селектор текстових вузлів до jQuery як плагін.

У фрагменті нижче ви бачите, що я визначаю нову функцію jQuery, яка отримує всі (і лише) текстові вузли. Цю функцію можна пов'язати також, наприклад, з first()функцією. Я обробляю текстовий вузол і перевіряю, чи не порожній він після обрізки, оскільки пробіли, вкладки, нові рядки тощо також розпізнаються як текстові вузли. Якщо вам потрібні ці вузли, просто видаліть їх з оператора if у функції jQuery.

Я додав приклад, як замінити перший текстовий вузол і як замінити всі текстові вузли.

Такий підхід полегшує читання коду та простіше використовувати його кілька разів та з різною метою.

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


Ага! Я знав, що десь буде розумна функція jQuery. Єдина проблема з рішенням, як ви написали, полягає в тому, що кожен текстовий вузол отримує наступний текст (наприклад, включаючи той, який знаходиться в дочірніх елементах). Я думаю, що це було б не надто важко обмежити?
— Пол Д. Уейт

10
У мене виникли проблеми з використанням .filter(':first'), але використання .first()замість цього працювало на мене. Дякую!
— hollaburoo

16
Це не працює для мене .text()(див. Цю jsfiddle ), але це стосується .replaceWith()( jsfiddle тут ).
— magicalex

2
Це працює для мене, некрасиво, оскільки це textObject = $ (myNode) .contents (). Filter (function () {return this.nodeType == 3;}) [0] $ (textObject) .replaceWith ("мій текст" );
— Мараги

кому цікаво 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
На сьогодні найкраще рішення, на яке я потрапив. Елегантний і простий.
— Йоав Кадош

3
Однак це не збереже порядок вузлів. наприклад, якщо текст був у кінці елемента спочатку, то він був би на початку.
— Мет

Він не збереже порядок, але в більшості випадків ви хочете, щоб текст був першим або останнім вузлом. Тож якщо додаток () не дає бажаного результату, спробуйте prepend (), якщо ви хочете, щоб наявні діти передували тексту.
— Сенсей

До сих пір найкоротший і просте рішення - 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>

Вуаля!

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

Це найкраще рішення!
— Гладкий вигляд

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

Ось ще один метод: 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>

ПІДКЛЮЧЕННЯ

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

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
Я думаю, що не. Здається, що ОП шукає спосіб змінити текст, а не додати новий текст.
— Метт Бал

0

Проста відповідь:

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

0

Проблема з відповіддю Марка полягає в тому, що ви також отримуєте порожні текстові коди. Рішення як плагін 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 року - коротка та проста

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

Пояснення

document.querySelector('#your-div-id') використовується для вибору батьків (елемент, текст якого ви збираєтеся змінити)

.childNodes[0] вибирає текстовий вузол

.nodeValue = 'new text' встановлює значення текстового вузла на "новий текст"


Можливо, ця відповідь надихнула коментаря Діна Мартіна. Не можу сказати точно, оскільки я вже багато років використовую це рішення. Я просто подумав, що я повинен розмістити цю ймовірність тут, тому що деякі люди переймаються цим більше, ніж тим, що це найкраще рішення.


2
Ви щойно скопіювали коментар Діна Мартіна з 2014 року і заявили про це як своє рішення на 2019 рік. Також використовуйте непотрібне поєднання jQuery та звичайного Javascript, що, на мою думку, є поганою практикою для гарної читабельності. Останнє ви не розміщували деталей про те, як працює ваше рішення. Це не найскладніше, але це не так, і це, мабуть, досить нові програмісти, які читають це, хто може скористатись додатковим поясненням, наприклад, що ви отримуєте нативний вузол DOM від об’єкта jQuery, отримуючи доступ до індексу масиву.
— Марк Байєнс

@MarkBaijens Я думаю, ти можеш мати рацію, коментар Діна Мартіна може бути там, де я отримав цей фрагмент років тому. У будь-якому разі, я використовую його з тих пір і просто скопіював це з мого персонального коду репо (де я перелічу корисні сценарії) у січні. Додано більш детальне пояснення та видалено зайвий jQuery.
— Silver Ringvee

Це, безумовно, найпростіше рішення, яке насправді працює, і люди повинні його використовувати, хоча ви не отримаєте жодних кудосів, щоб заставити його як власне, не надаючи кредиту Діну Мартіну. Я також погоджуюся з Марком Бейенсом, що чиста реалізація Vanilla JS в цьому випадку краще, ніж змішування jQuery і Vanilla JS. Не тільки для кращої читабельності, але й для покращення продуктивності, оскільки jQuery уповільнює роботу.
— Miqi180

@ Miqi180 - як я вже говорив вище, це можливо, я не пам'ятаю, де я вперше отримав це рішення. Я вже багато років використовую його у своїй роботі. У відповідь додано примітку. Сподіваємось, це допомагає людям на кшталт вас, котрим не
— цікаво
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.