Скрипты и обработка событий
Вы можете добавить интерактивность в компоненты 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.