Code Ready | Frontend
21.6K subscribers
1.27K photos
534 videos
17 files
997 links
Авторский канал по Frontend разработке.
Ресурсы, гайды, задачи, шпаргалки.
Информация ежедневно пополняется!

Cотрудничество: @energy_c

РКН: https://clck.ru/3NJCKs
Download Telegram
dataset: работа с data-* без getAttribute() и setAttribute()!

HTML-атрибуты data-* позволяют хранить данные, непосредственно связанные с конкретным DOM-элементом. Для доступа к таким значениям DOM предоставляет стандартный API dataset.
<button
data-user-id="42"
data-action="delete"
>
Удалить
</button>


Свойство dataset возвращает объект DOMStringMap, через который можно читать значения data-* как свойства JavaScript-объекта.
const button = document.querySelector('button');

console.log(button.dataset.userId);
// "42"

console.log(button.dataset.action);
// "delete"


При формировании имени свойства префикс data- удаляется, а дефис перед строчной ASCII-буквой a-z удаляется, при этом следующая буква преобразуется в верхний регистр. Поэтому data-user-role становится dataset.userRole.
<div
id="user"
data-user-role="admin"
></div>


Это преобразование выполняется самим DOM API, поэтому обращаться к исходному имени атрибута вручную не требуется.
const user = document.querySelector('#user');

console.log(user.dataset.userRole);
// "admin"


dataset поддерживает не только чтение. Присваивание свойства изменяет соответствующий data-* атрибут элемента.
button.dataset.action = 'restore';

console.log(button.getAttribute('data-action'));
// "restore"


Если соответствующего data-* атрибута ещё нет, присваивание через dataset создаст его в DOM.
button.dataset.loading = 'true';

console.log(button.hasAttribute('data-loading'));
// true


Удаление свойства через оператор delete удаляет и соответствующий атрибут элемента.
delete button.dataset.loading;

console.log(button.hasAttribute('data-loading'));
// false


Важная особенность dataset: значения представлены строками. При присваивании числа, boolean и другие значения преобразуются в строковое представление.
button.dataset.userId = 42;
button.dataset.active = true;

console.log(button.dataset.userId);
// "42"

console.log(button.dataset.active);
// "true"

console.log(typeof button.dataset.userId);
// "string"


Если приложению нужен другой тип, преобразование следует выполнять явно. Это особенно важно для чисел и boolean-значений, поскольку строка "false" в JavaScript сама по себе является truthy.
const userId = Number(button.dataset.userId);
const isActive = button.dataset.active === 'true';


Один из практических сценариев для data-* — делегирование событий. При этом использовать event.target.dataset напрямую не всегда корректно: фактической целью события может оказаться вложенный span, svg или другой дочерний элемент.
<ul id="users">
<li>
<button data-user-id="42">
<span>Удалить</span>
</button>
</li>
</ul>


Для такого случая надёжнее найти ближайший подходящий элемент через closest() и дополнительно проверить, что он относится к нужному контейнеру.
const list = document.querySelector('#users');

list.addEventListener('click', event => {
const button =
event.target.closest('[data-user-id]');

if (!button || !list.contains(button)) {
return;
}

const userId =
Number(button.dataset.userId);

removeUser(userId);
});


dataset хорошо подходит для небольших объёмов метаданных, принадлежащих конкретному DOM-элементу: идентификаторов, режимов, состояний интерфейса и параметров поведения.

Для сложных объектов и полноценного состояния приложения data-* использовать не стоит — DOM в таком случае фактически превращается в хранилище состояния, для которого существуют более подходящие структуры данных.
button.dataset.userId = '42';
button.dataset.action = 'delete';
button.dataset.confirm = 'true';


🔥 dataset — стандартный DOM API поверх data-*, который делает работу с пользовательскими атрибутами короче и удобнее, но не обеспечивает типизацию их значений: значения dataset представлены строками и при необходимости требуют явного преобразования.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍107🔥5
📱 Clipboard API — работа с буфером обмена!

В этой шпаргалке собраны основные методы Clipboard API для программной работы с буфером обмена. Здесь показано, как читать и записывать текстовые данные, работать с HTML, изображениями и другими поддерживаемыми MIME-типами, создавать ClipboardItem с несколькими представлениями данных, проверять поддержку форматов и извлекать содержимое нужного типа, а также использовать legacy-механизм копирования в качестве fallback.

📣 Code Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍166🔥6
👩‍💻 Этим атрибутом помечают обязательные поля формы!

Атрибут required добавляется обязательным полям формы. Если поле с таким атрибутом не заполнено, то при отправке формы браузер покажет предупреждение и отменит отправку.

Атрибут required можно использовать для <select>, <textarea>, а также для <input> со следующими типами:
text,
search,
url,
tel,
email,
password,
date,
month,
week,
time,
datetime-local,
number,
checkbox,
radio,
file.


Важно: этот атрибут проверяется только на стороне браузера. Для защиты данных всегда нужна дополнительная проверка на сервере, так как HTML-валидацию можно обойти.

📣 Code Ready | #атрибут
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥9🤝72
This media is not supported in your browser
VIEW IN TELEGRAM
😍 RS School Materials — большая подборка материалов для изучения frontend-разработки!

Здесь собраны полезные ресурсы по HTML, CSS, Flexbox, Grid, JavaScript, React, Git и Computer Science: учебники, статьи, интерактивные курсы, игры и задачи. Отдельные разделы посвящены JavaScript-проектам и подготовке к собеседованиям. Удобная подборка для начинающих.

Оставляю ссылочку: GitHub 📱


📣 Code Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥6🤝62
Передавай простые значения из HTML прямо в CSS!

Раньше attr() практически ассоциировался только с content. Расширенный синтаксис умеет читать атрибут как конкретный CSS-тип и использовать результат в обычных свойствах.

Например, прогресс можно хранить прямо в разметке:
<div class="progress" data-value="72"></div>


А ширину вычислить без style="width: 72% и без JS:
.progress {
width: calc(attr(data-value type(<number>)) * 1%);
}


То же самое работает с типизированными значениями. Например, компонент может получить цвет из data-*:
.badge {
background: attr(data-color type(<color>), gray);
}


Это удобно для серверного рендера и компонентов, где данные уже находятся в DOM, тк не нужно дублировать их в inline-style или генерировать отдельные классы.

Но пока расширенный attr() для произвольных свойств и type() ещё имеет неполную поддержку браузерами.

🔥 По сути, data-* теперь может быть небольшим типизированным API между разметкой и CSS.

📣 Code Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥76
❤️ Супер интересная статья попалась на Хабре: «CSS задачи на 200 IQ»!

В этой статье:
• Узнаете, как сделать аналог fixed-элемента внутри прокручиваемого контейнера;
• Разберёте необычный способ передачи параметров в SVG через CSS;
• Посмотрите, как scroll-driven animations помогают решить сложную задачу с автоматическим размером элементов.

🔊 Продолжай читать на Habr!


📣 Code Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍6🔥4🤝2
Разбираем insertAdjacentHTML() — вставляем HTML без повторного парсинга существующего содержимого!

Для добавления разметки в элемент иногда используют innerHTML +=:
list.innerHTML += '<li>Новый элемент</li>';


Но это не точечная вставка. Браузер получает текущее содержимое как строку, добавляет новую разметку и снова устанавливает innerHTML.

В результате существующие дочерние DOM-узлы могут быть заменены новыми:
const button = list.querySelector('button');

list.innerHTML += '<li>Новый</li>';

console.log(
list.querySelector('button') === button
);
// false


Для вставки HTML без повторного парсинга существующего содержимого есть insertAdjacentHTML():
const button = list.querySelector('button');

list.insertAdjacentHTML(
'beforeend',
'<li>Новый</li>'
);

console.log(
list.querySelector('button') === button
);
// true


Метод принимает позицию вставки и HTML-строку:
beforebegin
afterbegin
beforeend
afterend


Например, вставка первым дочерним элементом:
list.insertAdjacentHTML(
'afterbegin',
'<li>Первый</li>'
);


А afterend вставляет разметку после самого элемента:
list.insertAdjacentHTML(
'afterend',
'<p>После списка</p>'
);


beforebegin и afterend работают относительно родительского элемента, поэтому целевой элемент должен иметь родителя.

Что важно: insertAdjacentHTML() передает строку HTML-парсеру и не выполняет санитизацию. Передача недоверенного HTML создает риск XSS. Для обычного текста используйте textContent или insertAdjacentText(), а недоверенный HTML необходимо корректно санитизировать.

🔥 В отличие от innerHTML +=, insertAdjacentHTML() позволяет вставить новый HTML-фрагмент в нужную позицию, не заменяя уже существующие DOM-узлы.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍137🔥5
Почему change не всегда подходит для отслеживания изменений в input!

При работе с формами часто пытаются отслеживать ввод через событие change:
input.addEventListener('change', event => {
console.log(event.target.value);
});


Но для текстовых полей это не всегда правильный вариант. change срабатывает не при каждом изменении текста, а после того, как пользователь изменил значение и завершил редактирование, например покинул поле.

Если интерфейс должен реагировать непосредственно во время ввода, используется событие input:
input.addEventListener('input', event => {
console.log(event.target.value);
});


Теперь обработчик вызывается при каждом изменении значения:
J
Ja
Jav
Java


При этом input — это не просто реакция на нажатие клавиш. Событие возникает и при других действиях пользователя, например при вставке текста, удалении, вставке через контекстное меню или перемещении текста через drag & drop.

Например, динамический поиск обычно строят так:
search.addEventListener('input', event => {
const query = event.target.value.trim();

filterItems(query);
});


Частая ошибка — использовать keyup как замену input:
input.addEventListener('keyup', handler);


Но эти события решают разные задачи. keyup реагирует только на отпускание клавиши, поэтому он не поймает вставку мышью, автозаполнение браузера и другие изменения значения без клавиатуры.

У события input есть дополнительная информация через InputEvent:
input.addEventListener('input', event => {
console.log(event.inputType);
});


Например, можно определить, было ли действие вставкой текста, удалением символа или вставкой из буфера обмена.

Если обработчик input запускает тяжёлую операцию или запрос к API, обычно используют debounce, чтобы не выполнять действие после каждого символа:
search.addEventListener(
'input',
debounce(event => {
fetchResults(event.target.value);
}, 300)
);


При этом у change остаются свои правильные сценарии. Например, для <select> он хорошо подходит, потому что важен момент выбора нового значения:
select.addEventListener('change', event => {
updateLanguage(event.target.value);
});


Важный нюанс: программное изменение value само по себе не создаёт событие input:
input.value = 'JavaScript';


Браузер отличает изменение через код от реального пользовательского ввода. Если приложению нужно уведомить другие части системы, событие можно вызвать отдельно:
input.value = 'JavaScript';

input.dispatchEvent(
new Event('input', { bubbles: true })
);


Но такое событие будет синтетическим (isTrusted === false), а не настоящим действием пользователя.

В сложных редакторах также учитывают IME-ввод, например при работе с китайской, японской или корейской раскладкой. Во время композиции можно проверить:
input.addEventListener('input', event => {
if (event.isComposing) {
return;
}

processValue(event.target.value);
});


🔥 Главное правило простое: если нужно реагировать на процесс редактирования в реальном времени — используйте input. Если нужно получить факт завершённого изменения значения — подходит change. Если нужно отслеживать только действия клавиатуры — используйте keyup, понимая его ограничения.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
13🤝10👍7🔥1
📱 AbortController — отмена запросов и асинхронных операций!

Разбираем AbortController и AbortSignal, с помощью которых можно отменять fetch-запросы и другие поддерживаемые операции, проверять состояние и причину отмены, прерывать собственную асинхронную логику, задавать таймауты и объединять несколько сигналов отмены. Используется для управления жизненным циклом операций, предотвращения лишней работы и корректной очистки ресурсов.

📣 Code Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥19👍9🤝32
👩‍💻 Удобный тег, объединяющий элементы навигации по сайту!

В контейнер <nav> помещаются основные ссылки, по которым пользователь сможет быстро перейти на нужный раздел сайта.

В <nav> обычно размещают:
главное меню сайта;
навигацию по разделам;
оглавление статьи или документа;
ссылки для перехода между связанными страницами.


При этом не каждую группу ссылок стоит помещать в <nav>. Тег предназначен прежде всего для основных навигационных блоков, а обычный набор вспомогательных ссылок может оставаться без него.

📣 Code Ready | #атрибут
Please open Telegram to view this post
VIEW IN TELEGRAM
👍119🤝4🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
👨‍💻 MilaNick materials — большая подборка материалов для frontend-разработчиков!

В репозитории собраны полезные ресурсы по веб-разработке: HTML, CSS, JavaScript, React, Node.js, Webpack, Git, тестирование и архитектура frontend-приложений. Есть статьи, курсы, видео, книги, разборы задач и практические материалы по асинхронности, ООП, алгоритмам, паттернам проектирования и созданию реальных проектов.

Оставляю ссылочку: GitHub 📱


📣 Code Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9🤝7👍4
Прокачать навыки вёрстки и фронтенда можно в телеграм!

В этом канале опытный верстальщик делится структурированными уроками и различными материалами по HTML, CSS, JS, а также советами по заработку на фрилансе.

Канал будет полезен:
1. начинающим и опытным верстальщикам
2. программистам
3. веб-дизайнерам

Научиться и зарабатывать на верстке:
@free_html_lessons