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

Кнопка "Поделиться" — 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.

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

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

Пошагово:

  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 и запасным вариантом (копирование ссылки):

Код 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-детали делают кнопку реально полезной, а не декоративной.


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

ПроверкаПочему важно
Кнопка работает на 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 как основа веб-интеграций.