Кнопка "Поделиться" — DOM, события и Web Share API
См. также: События · Асинхронность · Работа с HTML (DOM) · BOM и navigator · Копирование в буфер · Canvas 2D · Web API в браузере · Web API на практике - примеры кода
Задача
На странице есть кнопка "Поделиться". По клику пользователь должен отправить ссылку на текущую статью в мессенджер, почту или заметки — через привычное системное меню, как в мобильном браузере или в нативном приложении.
Для этого в современных браузерах есть Web Share API: метод navigator.share(). Скрипт не рисует своё окно со списком приложений — он передаёт данные операционной системе, а ОС показывает лист "Поделиться" (share sheet).
Ниже разберём учебный файл share.js построчно: от поиска кнопки в DOM до вызова API.
Интеграция Web Share API
Для пользователя — один клик и системный лист "Поделиться" (мессенджер, почта, заметки). Для разработчика — обработчик click, вызов navigator.share({ title, text, url }) и fallback (копирование URL), если API недоступен.
Разметка страницы
Сначала в HTML должна быть кнопка с классом, по которому скрипт её найдёт:
<button type="button" class="share-btn">Поделиться</button>
<script src="share.js"></script>
Разбор:
- В этом фрагменте используется конструкция
<button type="button" class="share-btn">Поделиться</button>как точка входа сценария. - Разметка задаёт опорные элементы интерфейса, к которым затем подключается JavaScript-логика.
- Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
Скрипт подключают после кнопки (или с атрибутом defer у <script src="share.js">), чтобы к моменту выполнения share.js элемент уже существовал в DOM. Подробнее о порядке загрузки — в работе с HTML.
| Часть | Роль |
|---|---|
type="button" | кнопка не отправляет форму случайно |
class="share-btn" | метка для CSS и для querySelector |
share.js | логика клика и вызов navigator.share |
document.querySelector — найти элемент на странице
DOM (Document Object Model) — дерево узлов HTML — теги, текст, атрибуты. JavaScript читает и меняет это дерево через объект document.
document.querySelector('.share-btn') ищет первый элемент, подходящий под CSS-селектор:
| Селектор в примере | Что ищет |
|---|---|
.share-btn | любой элемент с классом share-btn |
#id | элемент с заданным id |
button.share-btn | именно <button class="share-btn"> |
Результат сохраняют в константу:
const btn = document.querySelector('.share-btn');
Разбор:
-
В этом фрагменте используется конструкция
const btn = document.querySelector('.share-btn');как точка входа сценария. -
Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
-
Поиск элементов через
querySelectorявно привязывает сценарий к нужным узлам DOM. -
Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
-
Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
-
Если элемент найден — в
btnлежит ссылка на узел DOM (можно вешать обработчики, менять текст). -
Если нет —
btn === null. Вызовbtn.addEventListenerтогда упадёт с ошибкой; в продакшене добавляют проверкуif (!btn) return;.
querySelectorAll возвращает список всех совпадений — когда кнопок несколько. Для одной кнопки "Поделиться" достаточно querySelector.
Сравнение с getElementById и практика кэширования ссылок — в справочнике по DOM и работе с HTML.
Система событий в браузере
Событие — сигнал о том, что что-то произошло — пользователь кликнул, нажал клавишу, прокрутил страницу, сеть вернула ответ. Браузер создаёт объект Event (для клика — MouseEvent) и запускает цепочку обработчиков.
Упрощённая схема для клика по кнопке:
Разбор:
- Диаграмма визуализирует последовательность шагов и роли участников в сценарии.
- По стрелкам видно, где запускается действие, где идёт ожидание и где возвращается результат.
- Такой формат удобно использовать для сверки бизнес-логики с фактической реализацией в коде.
- После чтения схемы проще определить точки для логирования, обработки ошибок и улучшения UX.
Три идеи, которые пригодятся дальше:
- Источник события — обычно конкретный DOM-элемент (
btn), а не весьdocument. - Обработчик — функция, которую браузер вызывает, когда событие дошло до элемента.
- Очередь задач — обработчик клика попадает в очередь макрозадач; тяжёлая работа внутри него без
awaitможет подвиснуть интерфейс.navigator.share()асинхронный — его как раз ждут черезawait.
Полный список типов событий, фазы capture/bubble, stopPropagation и делегирование — в статье События.
addEventListener — подписаться на клик
Чтобы выполнить код после клика, регистрируют слушатель (обработчик):
btn.addEventListener('click', async () => {
// тело обработчика
});
Разбор:
- В этом фрагменте используется конструкция
btn.addEventListener('click', async () => {как точка входа сценария. - Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
- Подписка через
addEventListenerсвязывает поведение с действием пользователя и отделяет логику от HTML-разметки. - Используется асинхронное выполнение (
async/await), поэтому интерфейс остаётся отзывчивым, пока операция не завершится. - Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
| Аргумент | Значение |
|---|---|
'click' | тип события (щелчок основной кнопкой мыши или активация с клавиатуры) |
async () => { ... } | функция, которую вызовут при клике |
addEventListener лучше старого атрибута onclick="..." в HTML:
- можно повесить несколько обработчиков на одну кнопку;
- проще отписаться через
removeEventListener; - разметка остаётся без встроенного JS (удобнее CSP и тестам).
Обработчик можно записать и именованной функцией:
async function onShareClick() {
await navigator.share({ /* ... */ });
}
btn.addEventListener('click', onShareClick);
Разбор:
- В этом фрагменте используется конструкция
async function onShareClick() {как точка входа сценария. - Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
- Подписка через
addEventListenerсвязывает поведение с действием пользователя и отделяет логику от HTML-разметки. - Используется асинхронное выполнение (
async/await), поэтому интерфейс остаётся отзывчивым, пока операция не завершится. - Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
Для учебного примера достаточно стрелочной функции прямо в вызове.
Зачем async и await
navigator.share() возвращает Promise — "обещание" завершить операцию позже:
- пользователь выбрал приложение и отправил ссылку → Promise выполнен (fulfilled);
- пользователь закрыл окно без отправки → Promise отклонён (rejected, часто
AbortError); - API недоступен → rejected с другой ошибкой.
Пока Promise в ожидании, главный поток JavaScript свободен: страница продолжает реагировать на прокрутку и другие клики. Подробнее про Event Loop — в асинхронности.
async перед функцией разрешает await внутри:
btn.addEventListener('click', async () => {
await navigator.share({ title: '...', url: '...' });
console.log('Пользователь закончил диалог "Поделиться"');
});
Разбор:
- В этом фрагменте используется конструкция
btn.addEventListener('click', async () => {как точка входа сценария. - Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
- Подписка через
addEventListenerсвязывает поведение с действием пользователя и отделяет логику от HTML-разметки. - Используется асинхронное выполнение (
async/await), поэтому интерфейс остаётся отзывчивым, пока операция не завершится. - Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
| Ключевое слово | Роль |
|---|---|
async | функция всегда возвращает Promise; внутри можно await |
await | приостановить эту async-функцию, пока Promise не завершится |
Без await код пошёл бы дальше сразу, не дожидаясь закрытия системного окна:
// так делать не нужно для share
navigator.share({ url: location.href });
console.log('эта строка выполнится до выбора приложения');
Разбор:
- В этом фрагменте используется конструкция
// так делать не нужно для shareкак точка входа сценария. - Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
- Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
Для share почти всегда пишут await и оборачивают вызов в try/catch, чтобы обработать отмену пользователем.
Что такое "шаринг" и Web Share API
Шаринг (от англ. share — "поделиться") — передача заголовка, текста и URL из веб-страницы во внешнее приложение — Telegram, WhatsApp, почта, "Заметки" и т.д.
Web Share API — часть объекта navigator:
await navigator.share({
title: document.title,
text: 'Посмотри эту статью',
url: location.href,
});
Разбор:
- В этом фрагменте используется конструкция
await navigator.share({как точка входа сценария. - Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
- Используется асинхронное выполнение (
async/await), поэтому интерфейс остаётся отзывчивым, пока операция не завершится. - Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
| Поле | Откуда в примере | Что попадёт в системное окно |
|---|---|---|
title | document.title | заголовок вкладки (<title> в HTML) |
text | строка в коде | короткое сообщение рядом со ссылкой |
url | location.href | полный адрес страницы (схема, хост, путь, query) |
Браузер не гарантирует, что все три поля покажет каждое приложение в списке: мессенджер может взять только url, почта — title + text. Передавать имеет смысл всё, что помогает пользователю.
Системное окно "Поделиться" (share sheet) рисует ОС или оболочка браузера, не ваш CSS. На Android и iOS это привычная сетка иконок приложений; на десктопе в Chrome/Edge — компактное меню "Поделиться" или интеграция с установленными PWA.
Скрипт не знает, какое приложение выберут — только ждёт результат Promise.
Полный пример share.js с пояснениями
Код ITЗагрузка примера кода…
Разбор:
- В этом фрагменте используется конструкция
// 1. Найти кнопку в DOM (один раз при загрузке скрипта)как точка входа сценария. - Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
- Поиск элементов через
querySelectorявно привязывает сценарий к нужным узлам DOM. - Подписка через
addEventListenerсвязывает поведение с действием пользователя и отделяет логику от HTML-разметки. - Используется асинхронное выполнение (
async/await), поэтому интерфейс остаётся отзывчивым, пока операция не завершится. - Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
Пошагово:
const btn— ссылка на кнопку сохраняется при загрузке; при каждом клике заново искать элемент не нужно.addEventListener('click', ...)— браузер вызовет функцию только после действия пользователя (важно для политики безопасности:shareиз произвольного таймера без жеста часто запрещён).async () => { ... }— обработчик можетawaitPromise отshare.navigator.share({ ... })— передача данных в нативный UI.document.titleиlocation.href— встроенные свойства BOM: документ и текущий URL без ручной склейки строк.try/catch— отмена диалога даётAbortError; её обычно игнорируют, остальные ошибки логируют.
Тот же сценарий с проверкой поддержки API и запасным вариантом (копирование ссылки):
Код ITЗагрузка примера кода…
Разбор:
- В этом фрагменте используется конструкция
const btn = document.querySelector('.share-btn');как точка входа сценария. - Код показывает последовательность действий: получение данных, проверка условий и выполнение целевого действия.
- Поиск элементов через
querySelectorявно привязывает сценарий к нужным узлам DOM. - Подписка через
addEventListenerсвязывает поведение с действием пользователя и отделяет логику от HTML-разметки. - Используется асинхронное выполнение (
async/await), поэтому интерфейс остаётся отзывчивым, пока операция не завершится. - Ключевые вызовы и свойства опираются на стандартные API JavaScript/браузера, поэтому шаблон легко перенести в реальный проект.
- Такой пример удобно расширять обработкой ошибок, логированием и дополнительной валидацией входных данных.
См. также сниппет копирования в буфер.
Условия и ограничения
| Условие | Почему важно |
|---|---|
HTTPS (или localhost) | navigator.share и clipboard — защищённые контексты |
| Поддержка браузера | проверка 'share' in navigator |
| Жест пользователя | вызов из обработчика click / touch |
| Десктоп | Web Share есть в Chromium; в Firefox на Windows/macOS может не быть — нужен fallback |
| Файлы | navigator.share({ files: [file] }) — отдельное расширение API; в учебном примере только текст и URL |
navigator.canShare?.(data) (если есть) позволяет заранее проверить, примет ли система конкретный набор полей, и не показывать неработающую кнопку.
Web Share и буфер обмена
| Задача | API | Кто выбирает приложение |
|---|---|---|
| Скопировать ссылку в буфер | navigator.clipboard.writeText | пользователь сам вставляет (Ctrl+V) |
| Открыть меню "Поделиться" | navigator.share | пользователь в системном списке |
Оба метода живут у navigator, асинхронны и удобны с async/await. Share лучше подходит для мобильных сценариев "отправить другу"; clipboard — универсальный запасной путь на десктопе.
Связь с другими темами раздела
| Тема | Где углубиться |
|---|---|
| Поиск элементов, изменение DOM | Работа с HTML в JavaScript, Виджеты интерфейса на ванильном JavaScript |
| События, делегирование | События и обработка событий в браузере |
Promise, Event Loop, async/await | Асинхронное программирование в JavaScript |
LoadingButton, isLoading в React | Кнопка с загрузкой — React, Promise и поток обновлений |
window, location, navigator | Объектная модель браузера (BOM) |
ES-модули (type="module") | ES-модули в браузере и обзор Temporal API |
Практика UX для кнопки "Поделиться"
- Показ кнопки стоит привязывать к проверке
navigator.share, чтобы интерфейс сразу отражал возможности платформы. - Для десктопа полезен fallback "Скопировать ссылку".
- Для статей и карточек контента эффективнее передавать короткий
text, понятный без контекста. - В аналитике фиксируют только факт открытия сценария share и итог (успех/отмена), без персональных данных.
Небольшие UX-детали делают кнопку реально полезной, а не декоративной.
Готовый чек-лист перед релизом
| Проверка | Почему важно |
|---|---|
| Кнопка работает на HTTPS | API доступен только в безопасном контексте |
Есть обработка AbortError | отмена пользователем выглядит штатно |
| Есть fallback на clipboard | сценарий покрыт для браузеров без Web Share |
| Текст и заголовок не пустые | ссылки отправляются с понятным контекстом |
| Поведение протестировано на мобильном браузере | основной сценарий share проходит через телефон |
Краткий итог
querySelector('.share-btn')находит кнопку в DOM.addEventListener('click', ...)запускает код по действию пользователя.async/awaitдожидаются завершенияnavigator.share()без блокировки страницы.- Web Share API передаёт
title,textиurlв системное окно "Поделиться"; выбор приложения остаётся за пользователем и ОС. - Проверяйте поддержку API, обрабатывайте
AbortErrorи держите запасной вариант (буфер обмена илиpromptс URL).
Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.