Кнопка "Поделиться" — DOM, события и Web Share API
См. также: События · Асинхронность · Работа с HTML (DOM) · BOM и navigator · Копирование в буфер · Web API в браузере · Web API на практике - примеры кода
Задача
На странице есть кнопка "Поделиться". По клику пользователь должен отправить ссылку на текущую статью в мессенджер, почту или заметки — через привычное системное меню, как в мобильном браузере или в нативном приложении.
Для этого в современных браузерах есть Web Share API: метод navigator.share(). Скрипт не рисует своё окно со списком приложений — он передаёт данные операционной системе, а ОС показывает лист "Поделиться" (share sheet).
Ниже разберём учебный файл share.js построчно: от поиска кнопки в DOM до вызова API.
Плавный старт — почему пользователи любят этот сценарий
Кнопка "Поделиться" сокращает путь до действия в один клик. Пользователь остаётся в привычной системе: выбирает мессенджер, почту или заметки в нативном окне платформы.
Для разработчика это компактная интеграция: один обработчик click, один вызов navigator.share, плюс fallback для окружений без поддержки API.
Мини-кейс "до/после"
| Подход | Что видит пользователь |
|---|---|
| До | нужно копировать URL вручную и переключаться между приложениями |
| После | ссылка уходит через системный share-sheet за несколько секунд |
Разметка страницы
Сначала в HTML должна быть кнопка с классом, по которому скрипт её найдёт:
<button type="button" class="share-btn">Поделиться</button>
<script src="share.js"></script>
Скрипт подключают после кнопки (или с атрибутом 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');
- Если элемент найден — в
btnлежит ссылка на узел DOM (можно вешать обработчики, менять текст). - Если нет —
btn === null. Вызовbtn.addEventListenerтогда упадёт с ошибкой; в продакшене добавляют проверкуif (!btn) return;.
querySelectorAll возвращает список всех совпадений — когда кнопок несколько. Для одной кнопки "Поделиться" достаточно querySelector.
Сравнение с getElementById и практика кэширования ссылок — в справочнике по DOM и работе с HTML.
Система событий в браузере
Событие — сигнал о том, что что-то произошло: пользователь кликнул, нажал клавишу, прокрутил страницу, сеть вернула ответ. Браузер создаёт объект Event (для клика — MouseEvent) и запускает цепочку обработчиков.
Упрощённая схема для клика по кнопке:
Три идеи, которые пригодятся дальше:
- Источник события — обычно конкретный DOM-элемент (
btn), а не весьdocument. - Обработчик — функция, которую браузер вызывает, когда событие дошло до элемента.
- Очередь задач — обработчик клика попадает в очередь макрозадач; тяжёлая работа внутри него без
awaitможет подвиснуть интерфейс.navigator.share()асинхронный — его как раз ждут черезawait.
Полный список типов событий, фазы capture/bubble, stopPropagation и делегирование — в статье События.
addEventListener — подписаться на клик
Чтобы выполнить код после клика, регистрируют слушатель (обработчик):
btn.addEventListener('click', async () => {
// тело обработчика
});
| Аргумент | Значение |
|---|---|
'click' | тип события (щелчок основной кнопкой мыши или активация с клавиатуры) |
async () => { ... } | функция, которую вызовут при клике |
addEventListener лучше старого атрибута onclick="..." в HTML:
- можно повесить несколько обработчиков на одну кнопку;
- проще отписаться через
removeEventListener; - разметка остаётся без встроенного JS (удобнее CSP и тестам).
Обработчик можно записать и именованной функцией:
async function onShareClick() {
await navigator.share({ /* ... */ });
}
btn.addEventListener('click', onShareClick);
Для учебного примера достаточно стрелочной функции прямо в вызове.
Зачем 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('Пользователь закончил диалог "Поделиться"');
});
| Ключевое слово | Роль |
|---|---|
async | функция всегда возвращает Promise; внутри можно await |
await | приостановить эту async-функцию, пока Promise не завершится |
Без await код пошёл бы дальше сразу, не дожидаясь закрытия системного окна:
// так делать не нужно для share
navigator.share({ url: location.href });
console.log('эта строка выполнится до выбора приложения');
Для 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,
});
| Поле | Откуда в примере | Что попадёт в системное окно |
|---|---|---|
title | document.title | заголовок вкладки (<title> в HTML) |
text | строка в коде | короткое сообщение рядом со ссылкой |
url | location.href | полный адрес страницы (схема, хост, путь, query) |
Браузер не гарантирует, что все три поля покажет каждое приложение в списке: мессенджер может взять только url, почта — title + text. Передавать имеет смысл всё, что помогает пользователю.
Системное окно "Поделиться" (share sheet) рисует ОС или оболочка браузера, не ваш CSS. На Android и iOS это привычная сетка иконок приложений; на десктопе в Chrome/Edge — компактное меню "Поделиться" или интеграция с установленными PWA.
Скрипт не знает, какое приложение выберут — только ждёт результат Promise.
Полный пример share.js с пояснениями
// 1. Найти кнопку в DOM (один раз при загрузке скрипта)
const btn = document.querySelector('.share-btn');
// 2. На клик — асинхронно открыть системный диалог "Поделиться"
btn.addEventListener('click', async () => {
try {
await navigator.share({
title: document.title,
text: 'Check this out',
url: location.href,
});
} catch (err) {
// Пользователь закрыл окно — не ошибка разработки
if (err.name !== 'AbortError') {
console.error('Share failed:', err);
}
}
});
Пошагово:
const btn— ссылка на кнопку сохраняется при загрузке; при каждом клике заново искать элемент не нужно.addEventListener('click', ...)— браузер вызовет функцию только после действия пользователя (важно для политики безопасности:shareиз произвольного таймера без жеста часто запрещён).async () => { ... }— обработчик можетawaitPromise отshare.navigator.share({ ... })— передача данных в нативный UI.document.titleиlocation.href— встроенные свойства BOM: документ и текущий URL без ручной склейки строк.try/catch— отмена диалога даётAbortError; её обычно игнорируют, остальные ошибки логируют.
Тот же сценарий с проверкой поддержки API и запасным вариантом (копирование ссылки):
const btn = document.querySelector('.share-btn');
if (!btn) return;
btn.addEventListener('click', async () => {
const payload = {
title: document.title,
text: 'Посмотри эту статью',
url: location.href,
};
if (navigator.share) {
try {
await navigator.share(payload);
} catch (err) {
if (err.name !== 'AbortError') console.error(err);
}
return;
}
// Запасной путь: десктоп без Web Share — копируем URL
try {
await navigator.clipboard.writeText(payload.url);
alert('Ссылка скопирована в буфер обмена');
} catch {
prompt('Скопируйте ссылку:', payload.url);
}
});
См. также сниппет копирования в буфер.
Условия и ограничения
| Условие | Почему важно |
|---|---|
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 | 102.md, 34.md |
| События, делегирование | 23.md |
Promise, Event Loop, async/await | 21.md |
LoadingButton, isLoading в React | 45.md |
window, location, navigator | 41.md |
ES-модули (type="module") | 40.md |
Практика 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 как основа веб-интеграций.
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Основы JavaScript - стандарт ECMAScript, модель выполнения и базовые конструкции языка. JavaScript — это язык программирования, который позволяет создавать интерактивные веб-страницы, серверные приложения и мобильные программы. Для создания массивов используется литеральная нотация. Конструктор Array не применяется. Как работать с HTML-элементами, как их создавать, менять. Простые приложения на JavaScript - базовые сценарии, структура кода и быстрый старт с практическими примерами. Расширения файлов определяют способ обработки кода средой выполнения или компилятором. История JavaScript - происхождение языка, ключевые этапы развития и влияние на современный веб. Такое именование представляет собой соглашение между разработчиками. Классический JavaScript не обеспечивает реальной приватности через подчеркивания. JavaScript содержит набор зарезервированных слов, которые имеют специальное значение в языке. Эти слова нельзя использовать в качестве идентификаторов для переменных, функций или классов. Встроенные функции JavaScript - ключевые методы массивов, строк и объектов для повседневной разработки. Этот шаблон описывает подключение внешних функций, классов или значений из других файлов. Он используется в начале файла и определяет зависимости текущего модуля. JavaScript используется для создания кроссплатформенных мобильных приложений, которые работают на iOS и Android с использованием единой кодовой базы.Основы JavaScript
Что требуется знать перед началом изучения языка программирования JavaScript
Рекомендации по разработке на JavaScript
Работа с HTML в JavaScript
Простые приложения на JavaScript
Форматы JavaScript
История языка JavaScript
Синтаксис и пунктуация в JavaScript
Ключевые слова языка JavaScript
Встроенные функции JavaScript
Структура и подключение JavaScript-кода
Применение JavaScript в вебе и за его пределами