7,2 млн рублей призового фонда и реальные задачи космической отрасли 🚀
В сентябре пройдет серия КосмоХакатонов для студентов, молодых ученых и специалистов.
Участникам предстоит за два дня разработать собственное решение, поработать с экспертами и представить проект жюри.
Участников ждут:
🛰 реальные задачи космической отрасли
👥 команды от 3 до 5 человек
💻 очный и онлайн-форматы
🧑💻 работа с экспертами и трекерами
🏆 финал в Москве
Первый КосмоХакатон стартует уже 4 сентября в Ростове-на-Дону.
Дальше серия продолжится в Красноярске, Нижнем Новгороде, Благовещенске и Санкт-Петербурге, а завершится финалом в Москве.
Участие бесплатное. Присоединиться могут студенты, аспиранты, молодые ученые и специалисты от 18 лет.
🔗 Зарегистрироваться: https://космохакатон.рф
В сентябре пройдет серия КосмоХакатонов для студентов, молодых ученых и специалистов.
Участникам предстоит за два дня разработать собственное решение, поработать с экспертами и представить проект жюри.
Участников ждут:
🛰 реальные задачи космической отрасли
👥 команды от 3 до 5 человек
💻 очный и онлайн-форматы
🧑💻 работа с экспертами и трекерами
🏆 финал в Москве
Первый КосмоХакатон стартует уже 4 сентября в Ростове-на-Дону.
Дальше серия продолжится в Красноярске, Нижнем Новгороде, Благовещенске и Санкт-Петербурге, а завершится финалом в Москве.
Участие бесплатное. Присоединиться могут студенты, аспиранты, молодые ученые и специалисты от 18 лет.
🔗 Зарегистрироваться: https://космохакатон.рф
dataset: работа с data-* без getAttribute() и setAttribute()!
HTML-атрибуты
Свойство
При формировании имени свойства префикс
Это преобразование выполняется самим DOM API, поэтому обращаться к исходному имени атрибута вручную не требуется.
Если соответствующего
Удаление свойства через оператор
Важная особенность
Если приложению нужен другой тип, преобразование следует выполнять явно. Это особенно важно для чисел и boolean-значений, поскольку строка
Один из практических сценариев для
Для такого случая надёжнее найти ближайший подходящий элемент через
Для сложных объектов и полноценного состояния приложения
🔥
📣 Code Ready | #практика
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 представлены строками и при необходимости требуют явного преобразования.Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤7🔥5
В этой шпаргалке собраны основные методы Clipboard API для программной работы с буфером обмена. Здесь показано, как читать и записывать текстовые данные, работать с HTML, изображениями и другими поддерживаемыми MIME-типами, создавать ClipboardItem с несколькими представлениями данных, проверять поддержку форматов и извлекать содержимое нужного типа, а также использовать legacy-механизм копирования в качестве fallback.Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤6🔥6
Атрибут
required добавляется обязательным полям формы. Если поле с таким атрибутом не заполнено, то при отправке формы браузер покажет предупреждение и отменит отправку.Атрибут required можно использовать для <select>, <textarea>, а также для <input> со следующими типами:
• text,
• search,
• url,
• tel,
• email,
• password,
• date,
• month,
• week,
• time,
• datetime-local,
• number,
• checkbox,
• radio,
• file.
Важно: этот атрибут проверяется только на стороне браузера. Для защиты данных всегда нужна дополнительная проверка на сервере, так как HTML-валидацию можно обойти.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥9🤝7❤2
This media is not supported in your browser
VIEW IN TELEGRAM
Здесь собраны полезные ресурсы по HTML, CSS, Flexbox, Grid, JavaScript, React, Git и Computer Science: учебники, статьи, интерактивные курсы, игры и задачи. Отдельные разделы посвящены JavaScript-проектам и подготовке к собеседованиям. Удобная подборка для начинающих.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥6🤝6❤2
Передавай простые значения из HTML прямо в CSS!
Раньше
Например, прогресс можно хранить прямо в разметке:
А ширину вычислить без
То же самое работает с типизированными значениями. Например, компонент может получить цвет из
Это удобно для серверного рендера и компонентов, где данные уже находятся в DOM, тк не нужно дублировать их в
Но пока расширенный
🔥 По сути,
📣 Code Ready | #совет
Раньше
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.Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥7❤6
В этой статье:
• Узнаете, как сделать аналог fixed-элемента внутри прокручиваемого контейнера;• Разберёте необычный способ передачи параметров в SVG через CSS;• Посмотрите, как scroll-driven animations помогают решить сложную задачу с автоматическим размером элементов.🔊 Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍6🔥4🤝2
Разбираем insertAdjacentHTML() — вставляем HTML без повторного парсинга существующего содержимого!
Для добавления разметки в элемент иногда используют
Но это не точечная вставка. Браузер получает текущее содержимое как строку, добавляет новую разметку и снова устанавливает
В результате существующие дочерние DOM-узлы могут быть заменены новыми:
Для вставки HTML без повторного парсинга существующего содержимого есть
Метод принимает позицию вставки и HTML-строку:
Например, вставка первым дочерним элементом:
А
Что важно:
🔥 В отличие от
📣 Code Ready | #практика
Для добавления разметки в элемент иногда используют
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-узлы.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤7🔥5
Почему change не всегда подходит для отслеживания изменений в input!
При работе с формами часто пытаются отслеживать ввод через событие
Но для текстовых полей это не всегда правильный вариант.
Если интерфейс должен реагировать непосредственно во время ввода, используется событие
Теперь обработчик вызывается при каждом изменении значения:
При этом
Например, динамический поиск обычно строят так:
Частая ошибка — использовать
Но эти события решают разные задачи.
У события
Например, можно определить, было ли действие вставкой текста, удалением символа или вставкой из буфера обмена.
Если обработчик
При этом у
Важный нюанс: программное изменение
Браузер отличает изменение через код от реального пользовательского ввода. Если приложению нужно уведомить другие части системы, событие можно вызвать отдельно:
Но такое событие будет синтетическим (
В сложных редакторах также учитывают IME-ввод, например при работе с китайской, японской или корейской раскладкой. Во время композиции можно проверить:
🔥 Главное правило простое: если нужно реагировать на процесс редактирования в реальном времени — используйте
📣 Code Ready | #практика
При работе с формами часто пытаются отслеживать ввод через событие
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, понимая его ограничения.Please open Telegram to view this post
VIEW IN TELEGRAM
❤13🤝10👍7🔥1
Разбираем AbortController и AbortSignal, с помощью которых можно отменять fetch-запросы и другие поддерживаемые операции, проверять состояние и причину отмены, прерывать собственную асинхронную логику, задавать таймауты и объединять несколько сигналов отмены. Используется для управления жизненным циклом операций, предотвращения лишней работы и корректной очистки ресурсов.Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥19👍9🤝3❤2
В контейнер
<nav> помещаются основные ссылки, по которым пользователь сможет быстро перейти на нужный раздел сайта.В <nav> обычно размещают:
• главное меню сайта;
• навигацию по разделам;
• оглавление статьи или документа;
• ссылки для перехода между связанными страницами.
При этом не каждую группу ссылок стоит помещать в
<nav>. Тег предназначен прежде всего для основных навигационных блоков, а обычный набор вспомогательных ссылок может оставаться без него.Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤9🤝4🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
В репозитории собраны полезные ресурсы по веб-разработке: HTML, CSS, JavaScript, React, Node.js, Webpack, Git, тестирование и архитектура frontend-приложений. Есть статьи, курсы, видео, книги, разборы задач и практические материалы по асинхронности, ООП, алгоритмам, паттернам проектирования и созданию реальных проектов.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9🤝7👍4