Перейти к основному содержимому

Кнопка "Поделиться" — 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) и запускает цепочку обработчиков.

Упрощённая схема для клика по кнопке:

Три идеи, которые пригодятся дальше:

  1. Источник события — обычно конкретный DOM-элемент (btn), а не весь document.
  2. Обработчик — функция, которую браузер вызывает, когда событие дошло до элемента.
  3. Очередь задач — обработчик клика попадает в очередь макрозадач; тяжёлая работа внутри него без 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,
});
ПолеОткуда в примереЧто попадёт в системное окно
titledocument.titleзаголовок вкладки (<title> в HTML)
textстрока в кодекороткое сообщение рядом со ссылкой
urllocation.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);
}
}
});

Пошагово:

  1. const btn — ссылка на кнопку сохраняется при загрузке; при каждом клике заново искать элемент не нужно.
  2. addEventListener('click', ...) — браузер вызовет функцию только после действия пользователя (важно для политики безопасности: share из произвольного таймера без жеста часто запрещён).
  3. async () => { ... } — обработчик может await Promise от share.
  4. navigator.share({ ... }) — передача данных в нативный UI.
  5. document.title и location.href — встроенные свойства BOM: документ и текущий URL без ручной склейки строк.
  6. 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 — универсальный запасной путь на десктопе.


Связь с другими темами раздела

ТемаГде углубиться
Поиск элементов, изменение DOM102.md, 34.md
События, делегирование23.md
Promise, Event Loop, async/await21.md
LoadingButton, isLoading в React45.md
window, location, navigator41.md
ES-модули (type="module")40.md

Практика UX для кнопки "Поделиться"

  • Показ кнопки стоит привязывать к проверке navigator.share, чтобы интерфейс сразу отражал возможности платформы.
  • Для десктопа полезен fallback "Скопировать ссылку".
  • Для статей и карточек контента эффективнее передавать короткий text, понятный без контекста.
  • В аналитике фиксируют только факт открытия сценария share и итог (успех/отмена), без персональных данных.

Небольшие UX-детали делают кнопку реально полезной, а не декоративной.


Готовый чек-лист перед релизом

ПроверкаПочему важно
Кнопка работает на HTTPSAPI доступен только в безопасном контексте
Есть обработка AbortErrorотмена пользователем выглядит штатно
Есть fallback на clipboardсценарий покрыт для браузеров без Web Share
Текст и заголовок не пустыессылки отправляются с понятным контекстом
Поведение протестировано на мобильном браузереосновной сценарий share проходит через телефон

Краткий итог

  1. querySelector('.share-btn') находит кнопку в DOM.
  2. addEventListener('click', ...) запускает код по действию пользователя.
  3. async / await дожидаются завершения navigator.share() без блокировки страницы.
  4. Web Share API передаёт title, text и url в системное окно "Поделиться"; выбор приложения остаётся за пользователем и ОС.
  5. Проверяйте поддержку API, обрабатывайте AbortError и держите запасной вариант (буфер обмена или prompt с URL).

Основа по протоколу

Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.

См. также

Другие статьи этого же раздела в боковом меню (как на странице "О разделе").