Скрипты и обработка событий
Вы можете добавить интерактивность в компоненты Astro без использования UI-фреймворка, такого как React, Svelte, Vue и т. д., используя стандартный HTML тег <script>. Это позволяет отправлять JavaScript в браузер и добавлять функциональность в компоненты Astro.
Клиентские скрипты
Заголовок раздела Клиентские скриптыСкрипты могут использоваться для того, чтобы добавить обработчики событий, отправить аналитические данные, анимировать элементы и многого другого, что JavaScript может делать в Интернете.
<button data-confetti-button>Celebrate!</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>, добавляя поддержку импорта модулей npm, написания TypeScript и т. д.
Использование <script> в Astro
Заголовок раздела Использование <script> в AstroВ файлы .astro можно добавить клиентский JavaScript, добавив один (или несколько) тегов <script>.
В этом примере добавление компонента <Hello /> на страницу приведет к выводу сообщения в консоль браузера.
<h1>Welcome, world!</h1>
<script>  console.log('Welcome, browser console!');</script>Обработка скриптов
Заголовок раздела Обработка скриптовПо умолчанию теги <script> обрабатываются Astro.
- Любые импорты будут скомпонованы, что позволит вам импортировать локальные файлы или модули Node.
- Обработанный скрипт будет вставлен в <head>вашей страницы с помощьюtype="module".
- TypeScript поддерживается полностью, включая импорт файлов TypeScript.
- Если ваш компонент используется на странице несколько раз, скрипт будет добавлен в сборку и на страницу только единожды.
<script>  // Обработан! Собран! Поддерживает TypeScript!  // Импорт локальных скриптов и модулей Node работает.</script>Атрибут type="module" заставляет браузер воспринимать скрипт как модуль JavaScript. Это дает несколько преимуществ в плане производительности:
- Рендеринг не блокируется. Браузер продолжает обрабатывать остальную часть HTML, пока загружается скрипт модуля и его зависимости.
- Браузер ожидает обработки HTML перед выполнением модульных скриптов. Вам не нужно прослушивать событие “load”.
- Атрибуты asyncиdeferне нужны. Модульные скрипты всегда откладываются.
Атрибут async полезен для обычных скриптов, поскольку он не позволяет им блокировать рендеринг. Однако модульные скрипты уже имеют такое поведение. Добавление async к модульному скрипту приведет к тому, что он будет выполняться до полной загрузки страницы. Вероятно, это не то, что вам нужно.
Отказ от обработки
Заголовок раздела Отказ от обработкиЧтобы запретить Astro обрабатывать скрипт, добавьте директиву is:inline.
<script is:inline>  // Будет выведено в HTML именно так, как написано!  // Локальные импорты не разрешены и не будут работать.  // Если в компоненте, то повторяется каждый раз, когда компонент используется.</script>В некоторых ситуациях Astro не будет обрабатывать теги скриптов. В частности, добавление type="module" или любого другого атрибута, кроме src, к тегу <script> приведет к тому, что Astro будет обрабатывать тег так, как если бы он содержал директиву is:inline. То же самое будет справедливо, если скрипт записан в выражении JSX.
<script> смотрите на странице справочника директив.
Включение файлов javascript на страницу
Заголовок раздела Включение файлов javascript на страницуВозможно, вы захотите написать свои скрипты в виде отдельных файлов .js/.ts или вам понадобится сослаться на внешний скрипт на другом сервере. Вы можете сделать это, сославшись на них в атрибуте <script> тега “src`.
Импорт локальных скриптов
Заголовок раздела Импорт локальных скриптовКогда это использовать: когда ваш скрипт находится внутри 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">Click me!</button>
<script>  // Находит все кнопки с классом `alert` на странице.  const buttons = document.querySelectorAll('button.alert');
  // Обрабатывает клик на всех кнопках.  buttons.forEach((button) => {    button.addEventListener('click', () => {      alert('Button was clicked!');    });  });</script>Если на странице имеется несколько компонентов <AlertButton />, Astro не будет запускать скрипт несколько раз. Скрипты собираются и добавляются на страницу единожды. Использование querySelectorAll гарантирует, что скрипт добавит обработчики событий к каждой кнопке с классом alert, найденной на странице.
Веб-компоненты с пользовательскими элементами
Заголовок раздела Веб-компоненты с пользовательскими элементамиВы можете создавать собственные HTML-элементы с пользовательским поведением, используя стандарт Web Components. Определение пользовательского элемента в компоненте .astro позволяет создавать интерактивные компоненты без использования библиотеки UI-фреймворка.
В этом примере мы определяем новый HTML-элемент <astro-heart>, который отслеживает количество нажатий на кнопку сердца и обновляет <span> актуальным значением.
<!-- Оборачиваем компонент в наш пользовательский элемент "astro-heart". --><astro-heart>  <button aria-label="Heart">💜</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.toString();      });    }  }
  // Сообщаем браузеру, чтобы он использовал наш класс AstroHeart для элементов <astro-heart>.  customElements.define('astro-heart', AstroHeart);</script>Использование пользовательского элемента здесь имеет два преимущества:
- 
Вместо поиска по всей странице с помощью document.querySelector(), вы можете использоватьthis.querySelector(), который ищет только в пределах текущего экземпляра пользовательского элемента. Это позволяет упростить работу с дочерними элементами внутри элемента.
- 
Хотя <script>выполняется только один раз, браузер будет запускать методconstructor()нашего пользовательского элемента каждый раз, когда найдет на странице<astro-heart>. Это означает, что вы можете смело писать код для одного компонента, даже если собираетесь использовать этот компонент несколько раз на странице.
Передача переменных frontmatter в скрипты
Заголовок раздела Передача переменных frontmatter в скриптыВ компонентах Astro код в frontmatter между кодовым забором --- выполняется на сервере и недоступен в браузере. Чтобы передавать переменные с сервера на клиент, нам нужен способ хранить наши переменные и затем считывать их при запуске JavaScript в браузере.
Один из способов сделать это - использовать атрибуты data-* для хранения значений переменных в HTML-выводах. Скрипты, включая пользовательские элементы, могут считывать эти атрибуты с помощью свойства dataset элемента, когда HTML загружается в браузере.
В этом примере компонента свойство message хранится в атрибуте data-message, поэтому пользовательский элемент может прочитать this.dataset.message и получить значение этого свойства в браузере.
---const { message = 'Welcome, world!' } = Astro.props;---
<!-- Храним реквизит сообщения как атрибут данных. --><astro-greet data-message={message}>  <button>Say hi!</button></astro-greet>
<script>  class AstroGreet extends HTMLElement {    constructor() {      super();
      // Считываем сообщение из атрибута данных.      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';---
<!-- Используйте сообщение по умолчанию: “Welcome, world!” --><AstroGreet />
<!-- Использовать пользовательские сообщения, передаваемые в качестве пропса. --><AstroGreet message="Lovely day to build components!" /><AstroGreet message="Glad you made it! 👋" />Это как раз то, что Astro делает под капотом, когда вы передаете пропсы компоненту, написанному с использованием UI-фреймворка, например React! Для компонентов с директивой client:* Astro создаёт кастомный элемент <astro-island> с атрибутом props, который и хранит все серверные данные в HTML.