W3docs

JavaScript — изменение документа

Как изменять DOM с помощью JavaScript: создавать, вставлять, заменять и удалять узлы, использовать insertAdjacentHTML, textContent и innerHTML.

JavaScript позволяет изменять страницу после её загрузки: добавлять новые элементы, перемещать их, обновлять текст, менять атрибуты и удалять то, что больше не нужно пользователю. Это основа любого динамического интерфейса — от отображения сообщения о валидации до рендеринга целого списка результатов поиска.

На этой странице рассматривается практический набор инструментов для изменения DOM: создание и вставка узлов, разница между textContent и innerHTML, быстрая вставка HTML с помощью insertAdjacentHTML, удаление и замена узлов, а также использование DocumentFragment для ускорения обновлений. Чтобы найти элементы, которые нужно изменить, см. Поиск: getElement* и querySelector*. Для понимания общей картины того, как страница структурирована в виде дерева узлов, см. Понимание узлов DOM.

Создание новых узлов

Прежде чем вставить что-либо на страницу, это нужно создать. Есть два основных строительных блока: узлы-элементы (<div>, <li>, …) и текстовые узлы (обычный текст).

Создание элементов

Новые элементы создаются с помощью метода document.createElement(tag). Элемент существует только в памяти до тех пор, пока он не вставлен в документ — до этого момента пользователь ничего не видит. Вот как создать div и добавить его на страницу:


<body></body>
<script>
  let div = document.createElement('div');
  div.innerHTML = "Hello, world!";
  document.body.appendChild(div);
</script>

Элемент появится только после того, как appendChild (или другой метод вставки) прикрепит его к узлу, уже находящемуся в документе.

Создание текстовых узлов

Для добавления обычного текста используется document.createTextNode(text). В отличие от innerHTML, текстовый узел обрабатывает содержимое буквально — <b> остаётся символами <b>, а не превращается в тег жирного шрифта. Это делает текстовые узлы безопасным выбором, когда текст приходит от пользователя или из любого ненадёжного источника:


<body>
  <div id="container"></div>
</body>
<script>
  const div = document.getElementById("container");
  let textNode = document.createTextNode('Here is some text');
  div.appendChild(textNode);
</script>

Вставка узлов

Когда узел создан, его нужно куда-то поместить. Классический метод — parent.appendChild(node), который добавляет узел последним дочерним элементом. Современные браузеры также предоставляют более гибкое семейство методов, принимающих как узлы, так и строки:

МетодКуда вставляет
node.append(...)В конец, внутрь node
node.prepend(...)В начало, внутрь node
node.before(...)Непосредственно перед node
node.after(...)Непосредственно после node
node.replaceWith(...)Полностью заменяет node

Здесь append и prepend добавляют элементы списка на противоположные концы <ul>:


<body>
  <ul id="list">
    <li>middle</li>
  </ul>
</body>
<script>
  const list = document.getElementById("list");

  const first = document.createElement("li");
  first.textContent = "first";
  list.prepend(first);

  const last = document.createElement("li");
  last.textContent = "last";
  list.append(last);
</script>

insertAdjacentHTML

Когда нужно вставить строку HTML относительно элемента — не затрагивая существующее содержимое — для этого подходит element.insertAdjacentHTML(position, html). Аргумент position — одно из четырёх ключевых слов:

  • "beforebegin" — перед самим элементом
  • "afterbegin" — внутри, перед первым дочерним элементом
  • "beforeend" — внутри, после последнего дочерního элемента
  • "afterend" — после самого элемента

<body>
  <div id="box">existing content</div>
</body>
<script>
  const box = document.getElementById("box");
  box.insertAdjacentHTML("beforeend", "<p>added inside, at the end</p>");
  box.insertAdjacentHTML("afterend", "<p>added after the box</p>");
</script>

Поскольку insertAdjacentHTML разбирает HTML-строку, никогда не передавайте в него ненадёжные данные — применяется тот же риск XSS, что и с innerHTML. Существуют методы-аналоги insertAdjacentText и insertAdjacentElement для вставки обычного текста или существующего узла в те же позиции.

textContent и innerHTML

Оба свойства задают содержимое элемента, но ведут себя совершенно по-разному:

  • innerHTML разбирает строку как HTML. el.innerHTML = "<b>Hi</b>" создаёт жирный узел. Присваивание заменяет все существующие дочерние элементы.
  • textContent обрабатывает строку как обычный текст. el.textContent = "<b>Hi</b>" показывает буквальные символы <b>Hi</b>.

Предпочитайте textContent при вставке текста — это быстрее и защищает от внедрения HTML/скриптов. Используйте innerHTML только тогда, когда действительно нужна разметка и источник заслуживает доверия.


<body>
  <div id="asHtml"></div>
  <div id="asText"></div>
</body>
<script>
  const input = "<b>3 < 5</b>";
  document.getElementById("asHtml").innerHTML = input;   // renders bold text
  document.getElementById("asText").textContent = input; // shows the literal markup
</script>

Изменение элементов

Изменение атрибутов

Чтобы изменить атрибут элемента, можно использовать element.setAttribute(name, value). Этот метод позволяет задать значение атрибута указанного элемента.


<body>
  <div id="firstID"></div>
  <div>new id is: <span id="result"></span></div>
</body>
<script>
  const div = document.getElementById("firstID");
  const result = document.getElementById("result");
  
  div.setAttribute("id", "newDiv");
  result.innerHTML = div.id;
</script>

Для более детального изучения различия между HTML-атрибутами и свойствами DOM (и когда использовать setAttribute, а когда прямой доступ к свойству, например el.id = "..."), см. Атрибуты и свойства.

Расширенные манипуляции

Клонирование элементов

Копию элемента можно создать с помощью метода element.cloneNode(deep). При значении deep равном true клонируется элемент вместе со всеми его потомками.


<body>
  <div id="mydiv">one div here, or two divs if cloned! <span>And here is a span inside the div!</span></div>
</body>
<script>
  const div = document.getElementById("mydiv");
  const clone = div.cloneNode(true);
  document.body.appendChild(clone);
</script>

Замена элементов

Чтобы заменить один узел другим, вызовите element.replaceWith(newNode). Старый узел удаляется из документа, а новый занимает его место:


<body>
  <p id="old">I will be replaced.</p>
</body>
<script>
  const old = document.getElementById("old");
  const fresh = document.createElement("p");
  fresh.textContent = "I am the replacement.";
  old.replaceWith(fresh);
</script>

Удаление элементов

Чтобы удалить элемент из DOM, используйте element.remove().


<body>
  <div>It's the only thing you see, as the next div is removed!</div>
  <div id="mydiv">you don't see me if I'm removed!</div>
</body>
<script>
  const div = document.getElementById("mydiv");
  div.remove();
</script>

Пакетные обновления с DocumentFragment

Каждый раз, когда вы вставляете узел в живой документ, браузер может пересчитывать макет. Вставка множества узлов в цикле по одному за раз может поэтому оказаться медленной. DocumentFragment — это лёгкий внеэкранный контейнер: вы собираете в нём все узлы, а затем вставляете фрагмент один раз. В DOM попадают только его дочерние элементы — сам фрагмент исчезает.


<body>
  <ul id="list"></ul>
</body>
<script>
  const list = document.getElementById("list");
  const fragment = document.createDocumentFragment();

  for (let i = 1; i <= 5; i++) {
    const li = document.createElement("li");
    li.textContent = "Item " + i;
    fragment.appendChild(li);
  }

  // One single insertion into the live document
  list.appendChild(fragment);
</script>

Другие способы поддерживать эффективность обновлений DOM см. в Оптимизация производительности DOM. Если ваша разметка используется повторно, элемент <template> — ещё один быстрый способ клонировать готовую структуру.

Практический пример: создание списка задач

Применим эти концепции для создания простого списка задач на JavaScript:


<body></body>
<script>
// Creating the list container
let list = document.createElement('ul');
document.body.appendChild(list);

// Adding items to the list
function addItem(text) {
    let item = document.createElement('li');
    item.textContent = text;
    list.appendChild(item);
}

addItem('Learn JavaScript');
addItem('Build a to-do list');
</script>

Заключение

Изменение документа — это основа любого динамического интерфейса: создавайте узлы с помощью createElement/createTextNode, размещайте их с помощью append/prepend/before/after или insertAdjacentHTML, выбирайте textContent для безопасного текста и innerHTML только для доверенной разметки, а DocumentFragment используйте для ускорения массовых обновлений. Применяйте replaceWith и remove для замены или удаления узлов.

Для дальнейшего изучения см. Манипуляции с DOM для общего обзора, Обход DOM для перемещения между связанными узлами и Свойства узла: тип, тег и содержимое, чтобы понять, что содержит каждый узел.

Практика

Практика
Какой метод можно использовать в JavaScript для изменения атрибута элемента?
Какой метод можно использовать в JavaScript для изменения атрибута элемента?
Was this page helpful?