DOM модель

Document Object Model (DOM)

Когда HTML-страница загружается в браузер, он создает объектную модель документа — DOM (Document Object Model). Проще говоря, DOM представляет структуру HTML-документа в виде дерева объектов (узлов). Каждый HTML-тег становится узлом-элементом, вложенные теги становятся дочерними узлами и т.д. Текст внутри тегов также становится отдельными узлами (текстовыми). Корневым узлом дерева является объект document, представляющий всю страницу.

DOM Model

DOM предоставляет программный интерфейс для работы с веб-страницей. С помощью JavaScript можно получить доступ к любому элементу страницы через DOM и изменить его содержимое, атрибуты или стили; можно создавать новые элементы и узлы, удалять существующие или перемещать их, а также реагировать на действия пользователя.

Основные операции с DOM

Рассмотрим распространённые задачи при работе с DOM и соответствующие им методы:

Поиск элементов на странице: Прежде чем изменить элемент, нужно получить к нему ссылку.

  • document.getElementById("id") – возвращает элемент по уникальному атрибуту id.
  • document.querySelector("селектор") – возвращает первый элемент, соответствующий CSS-селектору (как в стилях). Например, document.querySelector(".menu li") найдёт первый элемент
  • внутри элемента с классом menu.
  • document.querySelectorAll("селектор") – возвращает список всех элементов, подходящих под селектор (статический NodeList). Например, document.querySelectorAll(“p”) вернёт коллекцию абзацев. По ней можно итерироваться (она похожа на массив). Пример:
let header = document.getElementById("main-header");
let items = document.querySelectorAll(".item");
console.log(header.innerText);              // текущее содержимое заголовка
console.log("Найдено элементов:", items.length);

Здесь мы нашли элемент с id “main-header” и все элементы с классом “item”.


Чтение и изменение содержимого: У DOM-узлов есть свойства для работы с их содержимым.

  • element.textContent – получить или изменить только текст внутри элемента (без тегов).
  • element.innerHTML – получить или заменить HTML-код внутри элемента (включая вложенные теги).

Пример:

let title = document.getElementById("main-header");
title.textContent = "Новый заголовок";  // изменили текст заголовка

let list = document.querySelector("#user-list");
list.innerHTML = "<li>Пункт 1</li><li>Пункт 2</li>";  // вставили новый список внутрь элемента

В первом случае текст заголовка заменится на “Новый заголовок”. Во втором случае все существующие дочерние элементы #user-list удалятся и заменятся на указанные два <li>.


Изменение атрибутов и стилей: Через DOM можно менять любые атрибуты элемента (например, href у ссылок, src у изображений, value у полей ввода).

Каждый атрибут доступен как свойство объекта элемента: например, img.src = "cat.png" изменит путь картинки, link.href = "/home" изменит адрес ссылки.

Для работы со стилями существует свойство element.style, через которое можно устанавливать CSS-свойства:

let box = document.querySelector(".alert");
box.style.backgroundColor = "yellow";
box.style.fontSize = "20px";

Это задаст элементу с классом alert жёлтый фон и размер шрифта 20px.

Обратите внимание: имена CSS-свойств, состоящие из двух слов (например, background-color), преобразуются в camelCase (backgroundColor).


Управление классами: часто выгоднее манипулировать не отдельными стилями, а классами элемента (классы обычно связаны с CSS-правилами). Для этого у узла есть свойство classList:

box.classList.add("active");             // добавить класс
box.classList.remove("hidden");          // убрать класс
box.classList.toggle("highlighted");     // переключить класс (если не было – добавить, было – убрать)

Изменяя классы, мы косвенно меняем оформление элемента согласно CSS-правилам.


Создание и удаление элементов: DOM позволяет создавать новые узлы и вставлять их на страницу, а также удалять существующие.

  • Создать новый элемент: document.createElement("tagName"). Пример: let newDiv = document.createElement("div");.
  • Создать новый текстовый узел: document.createTextNode("просто текст") (чаще текст вставляют через textContent сразу в элемент).
  • Вставить элемент в документ: нужно указать, куда вставляем:
    • parent.appendChild(node) – добавляет node в конец списка дочерних элементов parent.
    • parent.insertBefore(newNode, referenceNode) – вставляет newNode перед указанным дочерним элементом referenceNode.
  • Удалить элемент: parent.removeChild(node) – удаляет элемент node, являющийся дочерним для parent.

    Или метод самого элемента: node.remove().

Например:

// Создадим новый абзац и добавим его в конец <body>
let paragraph = document.createElement("p");
paragraph.textContent = "Привет! Я новый абзац.";
document.body.appendChild(paragraph);

// Удалим первый элемент списка с id="user-list"
let list = document.getElementById("user-list");
let firstItem = list.querySelector("li");
list.removeChild(firstItem);

В примере сначала создаётся новый <p> с текстом и добавляется на страницу. Затем из списка #user-list удаляется первый пункт.


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

Для назначения обработчика события используют метод element.addEventListener(event, handler). Первый аргумент – имя события (например, “click”, “input”, “submit”), второй – функция-обработчик. Например:

let btn = document.getElementById("sendButton");
btn.addEventListener("click", function(event) {
  alert("Кнопка нажата!");
});

Здесь при клике по элементу с id "sendButton" выполнится функция, показывающая браузерное сообщение с текстом. Обработчик получает объект события (часто обозначается event или e), из которого можно узнать детали (например, event.target – элемент, на котором случилось событие). В данном случае в обработчике event не используется.

Существует очень много различных обработчиков событий: keydown (нажатие клавиши), change (изменение значения поля), mouseover (курсор навёлся на элемент), mouseout (курсор ушёл) и т.д. Можно навесить несколько обработчиков на один элемент (они выполнятся в порядке добавления). Также есть старый способ – назначить обработчик через свойство, например, btn.onclick = function() { ... }, но он менее гибкий (можно назначить только один таким образом, перезаписывая предыдущий).


Комбинируя создание элементов и события, можно реализовывать динамически изменяемые интерфейсы. Например, добавим функциональность: нажатием кнопки добавлять новое поле ввода в форму (полезно для «добавить ещё один интерес» в анкете):

document.getElementById("addInterestButton").addEventListener("click", () => {
  // Создаём новое поле ввода типа text
  let newInput = document.createElement("input");
  newInput.type = "text";
  newInput.name = "interest";
  newInput.placeholder = "Ваш интерес";
  // Добавляем его в контейнер с id="interestList"
  document.getElementById("interestList").appendChild(newInput);
});

Каждый клик по кнопке с id "addInterestButton" выполнит этот код: создастся новый <input> и вставится в элемент-контейнер с id "interestList" (например, div в форме). Пользователь сможет динамически добавлять несколько интересов.

Работа с HTML формами

HTML-форма – это область страницы (<form>), предназначенная для ввода пользователя и отправки этих данных на сервер. Формы содержат интерактивные элементы: текстовые поля, выпадающие списки, флажки (checkbox), переключатели (radio), кнопки и т.д. JavaScript часто применяется для валидации (проверки) данных формы перед их отправкой, а также для улучшения UX (подсказки при вводе, динамическое добавление полей и пр.).

Пример простой формы:

<form action="/submit" method="POST">
  <label for="name">Имя:</label>
  <input type="text" id="name" name="name" required><br><br>

  <label for="email">Email:</label>
  <input type="email" id="email" name="email" required><br><br>

  <label for="message">Сообщение:</label><br>
  <textarea id="message" name="message" rows="4" cols="40"></textarea><br><br>

  <button type="submit">Отправить</button>
</form>

Здесь:

  • <form action="/submit" method="POST"> – тег формы, атрибут action указывает URL (условно “/submit”), на который будут отправлены данные, method="POST" задаёт HTTP-метод. При нажатии на кнопку отправки браузер соберёт все поля и выполнит запрос по указанному адресу.
  • <label for="name"> – определяет метку для поля (при клике на текст метки курсор перейдёт в соответствующее поле). Связывание идёт через атрибут for, который совпадает с id поля.
  • <input type="text" id="name" name="name" required> – однострочное текстовое поле для ввода имени. Атрибут name очень важен: именно по нему это поле будет идентифицироваться на сервере. Атрибут required указывает, что поле обязательное (браузер сам проверит, что пользователь что-то ввёл, перед отправкой).
  • <input type="email" ... required> – поле для ввода email. Браузеры реализуют базовую проверку формата email (наличие символа @ и точки и др.).
  • <textarea id="message" name="message"> – многострочное поле для ввода произвольного текста сообщения.
  • <button type="submit"> – кнопка отправки формы. По нажатию, если скриптом не перехвачено и все обязательные поля заполнены, форма отправится на action.

Без JavaScript при нажатии кнопки страница перезагрузится и перейдёт на адрес, указанный в action (либо этой же странице, если action не задан). Но благодаря JS можно перехватить отправку, проверить данные, вывести подсказки, и только потом вручную отправить (или отправить запрос в фоне).

Валидация и обработка данных формы с помощью JavaScript

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

Самый распространённый подход – слушать событие submit на элементе <form>. Это событие происходит, когда пользователь пытается отправить форму (например, нажал кнопку submit). В обработчике этого события можно отменить стандартное действие и выполнить свою логику проверки.

Пример валидации формы с JavaScript:

let form = document.querySelector("form");
form.addEventListener("submit", function(event) {
  event.preventDefault(); // Отключаем стандартную отправку формы

  // Получаем значения полей
  let name = document.getElementById("name").value.trim();
  let email = document.getElementById("email").value.trim();
  let message = document.getElementById("message").value.trim();

  // Проверяем поля
  if (name === "" || email === "" || message === "") {
    alert("Пожалуйста, заполните все поля формы.");
    return; // прерываем выполнение обработчика
  }
  if (!email.includes("@")) {
    alert("Пожалуйста, введите корректный адрес email.");
    return;
  }
  if (message.length < 10) {
    alert("Сообщение слишком короткое (минимум 10 символов).");
    return;
  }

  // Если проверки пройдены:
  alert("Форма заполнена верно! Данные готовы к отправке.");
  // Тут можно отправить данные на сервер вручную через fetch/AJAX или позволить форме отправиться
  // form.submit(); // отправить форму традиционным способом
});

В этом коде:

  • event.preventDefault() предотвращает переход браузера по адресу в action. Форма не будет отправлена, пока мы явно не решим.
  • Метод .trim() убирает пробелы с концов введённых строк, чтобы предотвратить ситуацию, когда поле вроде не пустое, но заполнено только пробелами.
  • Проверки: если имя, email или сообщение пустые – показываем сообщение и выходим из функции (через return). Если в email нет символа “@” – тоже ошибка. Если сообщение короче 10 символов – сообщаем об этом.
  • Если ни одна проверка не вызвала return, значит все поля заполнены корректно. Мы показываем сообщение об успехе. В реальном приложении на этом месте можно отправить данные на сервер с помощью fetch или другого способа, либо вызвать form.submit() чтобы продолжить обычную отправку.

Таким образом, пользователь получает мгновенную обратную связь. Конечно, подобную проверку необходимо дублировать и на сервере, ведь пользователь может отключить JS или обойти страницу вовсе.

Практическое задание: Реализация формы обратной связи с валидацией

Цель: Научиться работать с формами и данными, введёнными пользователем. Освоить основные методы JavaScript для проверки данных формы.
Задание:

  1. Создайте форму с полями для ввода имени, email и сообщения.
  2. Используйте JavaScript для проверки, что все поля заполнены корректно:
    • Имя не должно быть пустым.
    • Email должен быть корректным.
    • Сообщение должно содержать хотя бы 10 символов.
  3. При успешной отправке формы выведите сообщение об успешной отправке. При ошибке выведите предупреждение с указанием, что необходимо исправить.

Самостоятельное задание

Часть 1: Расширенная форма с валидацией и динамическими элементами

Пользователь вводит данные в форму, видит подсказки о количестве символов в комментарии, может добавить новые интересы через динамические поля, и после валидации данные выводятся на экран.

Форма опроса

Создайте HTML-форму для опроса, которая включает следующие элементы:

  • Поле для ввода имени.
  • Поле для ввода возраста.
  • Переключатели (radio buttons) для выбора пола.
  • Чекбоксы для указания интересов (например, спорт, музыка, кино).
  • Многострочное текстовое поле для комментариев с отображением текущего количества введённых символов и лимитом в 200 символов.
  • Кнопка для динамического добавления новых полей для ввода интересов.

Валидация формы

  • Имя не должно быть пустым.
  • Возраст должен быть числом больше 0 и не старше 120.
  • Пользователь должен выбрать хотя бы один интерес.
  • Комментарий не должен превышать 200 символов.
  • Валидация новых полей, добавленных динамически.

Вывод данных формы

После успешной валидации формы выведите введённые данные на экран в структурированном виде:

  • Имя
  • Возраст
  • Пол
  • Интересы
  • Комментарии
Добавьте кнопку для динамического добавления полей для ввода новых интересов без перезагрузки страницы.

Один из вариантов реализации:

document.getElementById("addInterest").addEventListener("click", function() {
    let newInterest = document.createElement("input");
    newInterest.setAttribute("type", "text");
    newInterest.setAttribute("name", "interest");
    newInterest.setAttribute("placeholder", "Новый интерес");
    
    let interestList = document.getElementById("interestList");
    interestList.appendChild(newInterest);
});

Подсчёт символов

Реализуйте подсчёт символов в реальном времени для текстового поля комментариев и покажите пользователю, сколько символов осталось до лимита.