Скрипты и обработка событий
Вы можете добавить интерактивность к Astro компонентам, не используя UI фреймворк (EN) такой как React, Svelte, Vue и т.д. Интерактивности можно достичь, используя стандартный HTML тег <script>
. Это позволит вам отправить JavaScript в браузер и добавить функциональности вашим Astro компонентам.
Клиентские скрипты
Раздел, озаглавленный Клиентские скриптыСкрипты могут использоваться для того, чтобы добавить обработчики событий, отправить аналитические данные, анимировать элементы и многого другого, что JavaScript может делать на веб-сайтах.
<button data-confetti-button>Поздравляем!</button>
<script> // Импортируйте npm модуль. import confetti from 'canvas-confetti';
// Найти DOM элемент на странице. const buttons = document.querySelectorAll('[data-confetti-button]');
// Добавить обработчики событий на кнопки для воспроизведения конфетти при клике. buttons.forEach((button) => { button.addEventListener('click', () => confetti()); });</script>
По умолчанию, Astro обрабатывает и собирает <script>
теги, добавляя поддержку импортов, TypeScript’а и другие функции.
Использование <script>
в Astro
Раздел, озаглавленный Использование <script> в AstroВ .astro
файлах вы можете добавить клиентский JavaScript, добавив <script>
тег (может быть несколько <script>
тегов).
В примере ниже добавляется <Hello />
компонент, который залогирует сообщение в браузерную консоль.
<h1>Привет, Astro!</h1>
<script> console.log('Добро пожаловать в браузерную консоль!');</script>
Сборка скриптов
Раздел, озаглавленный Сборка скриптовПо умолчанию, <script>
теги обрабатываются Astro.
- Любые импорты будут добавлены в прод-сборку, позволяя использовать внешние зависимости, такие как локальные файлы и Node модули.
- Обработанный скрипт будет добавлен на страницу в
<head>
тег с типомtype="module"
. - TypeScript полностью поддерживается, включая импорт TypeScript файлов.
- Если ваш компонент используется несколько раз на странице, скрипт будет добавлен в сборку и на страницу только единожды.
<script> // Обработан! Собран! Поддерживает TypeScript! // Импорт локальных и Node модулей работает.</script>
Для того, чтобы избежать сборки скрипта, вы можете добавить директиву is:inline
.
<script is:inline> // Будет добавлен в HTML именно в таком виде, как написан! // Локальные импорты не поддерживаются и не будут работать. // Если используется в компоненте, то на страницу будет добавлен столько раз, сколько раз компонент используется.</script>
Поведение Astro сборки по умолчанию может быть отключено в некоторых случаях. А именно, добавление type="module"
или любого другого атрибута кроме src
к тегу <script>
приведёт к тому, что Astro будет интепретировать этот тег так же, как имеющий is:inline
директиву. То же самое произойдет, если скрипт будет описан в JSX выражении.
📚 Обратитесь к нашему описанию директив (EN) за более подробной информацией о доступных директивах для тегов <script>
.
Загрузка скриптов
Раздел, озаглавленный Загрузка скриптовВам может потребоваться описать свой скрипт в отдельном .js
/.ts
файле или подключить внешний скрипт с другого сервера. Этого можно достичь, добавив путь до файла в атрибут src
тега <script>
.
Импорт локальных скриптов
Раздел, озаглавленный Импорт локальных скриптовКогда использовать: Если ваш скрипт расположен в папке src/
.
Astro соберёт, оптимизирует и добавит эти скрипты на страницу, в соответствии с правилами сборки.
<!-- относительный путь до скрипта `src/scripts/local.js` --><script src="../scripts/local.js"></script>
<!-- так же работает для локальных TypeScript файлов --><script src="./script-with-types.ts"></script>
Загрузка внешних скриптов
Раздел, озаглавленный Загрузка внешних скриптовКогда использовать: Если ваш JavaScript файл расположен в локальной директории public/
, или, например, на CDN.
Для того, чтобы загрузить скрипты, которые расположены вне проектной директории src
, используйте директиву is:inline
. Этот подход позволяет пропустить JavaScript обработку, сборку и оптимизацию, которые предоставляются Astro.
<!-- абсолютный путь до скрипта `public/my-script.js` --><script is:inline src="/my-script.js"></script>
<!-- полный URL до скрипта на удалённом сервере --><script is:inline src="https://my-analytics.com/script.js"></script>
Распространнёные примеры использования скриптов
Раздел, озаглавленный Распространнёные примеры использования скриптовОбработка onclick
и других событий
Раздел, озаглавленный Обработка onclick и других событийНекоторые UI фреймворки используют особый синтаксис для обработки событий, как, например, onClick={...}
(React/Preact) или @click="..."
(Vue). Astro следует стандартам HTML и не использует собственный синтаксис обработки событий.
Вместо этого, для обработки пользовательских взаимодействий вы можете использовать addEventListener
внутри <script>
тега
<button class="alert">Кликни меня!</button>
<script> // Находит все кнопки с классом `alert` на странице. const buttons = document.querySelectorAll('button.alert');
// Обрабатывает клик на всех кнопках. buttons.forEach((button) => { button.addEventListener('click', () => { alert('Кнопка была нажата!'); }); });</script>
Если на вашей странице несколько <AlertButton />
, Astro не будет запускать скрипт несколько раз. Скрипты собраны и добавлены на страницу единожды. С помощью querySelectorAll
можно убедиться, что скрипт добавит обработчики событий на всех кнопки с alert
классом на странице.
Веб-компоненты с кастомными элементами
Раздел, озаглавленный Веб-компоненты с кастомными элементамиВы можете создавать свои собственные HTML элементы с произвольным поведением, используя стандарт Веб-компонент (Web Components). Определение своего элемента в .astro
файле позволяет создавать интерактивные компоненты без необходимости использования UI фреймворка.
В этом примере, мы определяем новый <astro-heart>
HTML элемент, который отслеживает количество нажатий на кнопку сердца и обновляет <span>
актуальным значением.
<!-- Оборачиваем компонент в свой элемент “astro-heart”. --><astro-heart> <button aria-label="Сердце">💜</button> × <span>0</span></astro-heart>
<script> // Определяем поведение для нового HTML элемента. class AstroHeart extends HTMLElement { constructor() { super(); let count = 0;
const heartButton = this.querySelector('button'); const countSpan = this.querySelector('span');
// Каждый раз когда кнопка нажата, обновляем счётчик. heartButton.addEventListener('click', () => { count++; countSpan.textContent = count; }); } }
// Оповещаем браузер, о том, что существует реализация для `astro-heart` тега. customElements.define('astro-heart', AstroHeart);</script>
Есть 2 преимущества использования кастомных элементов здесь:
-
Вместо того, чтобы искать элементы через
document.querySelector()
, здесь можно использоватьthis.querySelector()
, который ищет только внутри текущего экземпляра элемента. Это позволяет упростить работу с дочерними элементами внутри элемента. -
Хотя
<script>
будет выполнен единожды, браузер будет вызыватьconstructor()
кастомного элемента каждый раз, когда он встретит<astro-heart>
на странице. Это значит, что вы можете безопасно разрабатывать для одного компонента, даже если на странице таких компонентов будет множество.
📚 Вы можете получить больше информации о кастомных элементах на странице гайда web.dev’s Reusable Web Components и MDN’s Введение в кастомные компоненты.
Передать frontmatter переменные в скрипты
Раздел, озаглавленный Передать frontmatter переменные в скриптыВ компонентах Astro, код frontmatter, заключенный в конструкцию ---
, запускается на сервере и не доступен в браузере. Для того, чтобы отправить данные с сервера на клиент, нам нужен способ сохранения данных внутри HTML, с возможностью чтения в JavaScript рантайме в браузере.
Один из возможных путей — использование data-*
атрибутов для хранения данных в HTML документе. Скрипты, включая кастомные элементы, затем могут получить доступ к атрибутам, используя dataset
свойство, как только HTML будет полностью загружен.
В этом примере компонента свойство message
хранится в data-message
атрибуте, таким образом кастомный элемент может получить значение свойства через this.dataset.message
.
---const { message = 'Привет, Astro!' } = Astro.props;---
<!-- Сохранить свойство message как data атрибут. --><astro-greet data-message={message}> <button>Сказать "Привет!"</button></astro-greet>
<script> class AstroGreet extends HTMLElement { constructor() { super();
// Прочитаем message свойство из data атрибута. const message = this.dataset.message; const button = this.querySelector('button'); button.addEventListener('click', () => { alert(message); }); } }
customElements.define('astro-greet', AstroGreet);</script>
Теперь можно использовать компонент множество раз и увидеть разные приветственные сообщения.
---import AstroGreet from '../components/AstroGreet.astro';---
<!-- Сообщение по умолчанию: Привет, Astro!” --><AstroGreet />
<!-- Use custom messages passed as a props. --><AstroGreet message="Подходящий день для разработки компонент!" /><AstroGreet message="Вы это сделали! 👋" />
Это как раз то, что Astro делает под капотом, когда вы передаёте свойства компонентам, написанным на UI фреймворке (например, React)! Для компонентов с директивой client:*
Astro создаёт кастомный элемент <astro-island>
с атрибутом props
, который и хранит все серверные данные в HTML.