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

Скрипты и обработка событий

Вы можете добавлять JavaScript в браузер и наделять компоненты Astro функциональностью, используя теги <script> прямо в шаблоне компонента.

Скрипты позволяют обрабатывать события, обновлять контент динамически и добавлять интерактивность без необходимости использовать тяжелые UI-фреймворки, такие как React или Svelte. Это снижает объем загружаемого JavaScript и упрощает разработку.

Скрипты можно использовать для добавления слушателей событий, отправки аналитики, запуска анимаций и всего остального, что умеет JavaScript в браузере.

Astro автоматически улучшает стандартные HTML-теги <script>: добавляет поддержку TypeScript, объединяет файлы в бандлы и удаляет дубликаты.

src/components/ConfettiButton.astro
<button data-confetti-button>Отпраздновать!</button>
<script>
// Импорт из npm-пакета.
import confetti from 'canvas-confetti';
// Находим кнопку на странице.
const buttons = document.querySelectorAll('[data-confetti-button]');
// Добавляем обработчик события.
buttons.forEach((button) => {
button.addEventListener('click', () => confetti());
});
</script>
См. раздел необработанные скрипты, если поведение скриптов отличается от ожидаемого.

По умолчанию Astro обрабатывает теги <script> следующим образом (если у них нет дополнительных атрибутов, кроме src):

  • Поддержка TypeScript: Все скрипты по умолчанию считаются TypeScript.
  • Сборка импортов: Вы можете импортировать локальные файлы или модули npm.
  • Тип модуля: Скрипты автоматически получают type="module".
  • Дедупликация: Если компонент используется на странице несколько раз, его скрипт будет включен только один раз.
  • Автоматический инлайнинг: Если скрипт маленький, Astro вставит его прямо в HTML для уменьшения количества запросов.

Astro пропустит обработку <script>, если у тега есть любой атрибут, кроме src.

Вы можете использовать директиву is:inline, чтобы намеренно отключить обработку:

src/components/InlineScript.astro
<script is:inline>
// Этот код попадет в HTML без изменений.
// TypeScript и импорты здесь не поддерживаются.
// Код будет дублироваться для каждого экземпляра компонента.
</script>

Вы можете выносить код в отдельные файлы .js или .ts.

Используйте относительный путь в атрибуте src. Astro обработает такой файл по всем правилам.

<script src="../scripts/local.js"></script>

Для файлов вне папки src/ обязательно используйте директиву is:inline. Astro не будет оптимизировать такие скрипты.

<script is:inline src="/my-script.js"></script>
<script is:inline src="https://my-analytics.com/script.js"></script>

В отличие от некоторых фреймворков, Astro не использует кастомный синтаксис вроде onClick. Вместо этого используйте стандартный метод addEventListener внутри тега <script>.

<button class="alert">Нажми на меня!</button>
<script>
const buttons = document.querySelectorAll('button.alert');
buttons.forEach((button) => {
button.addEventListener('click', () => {
alert('Кнопка нажата!');
});
});
</script>

Вы можете создавать собственные HTML-элементы с помощью стандарта Web Components. Это отличный способ строить интерактивные компоненты без сторонних библиотек.

src/components/AstroHeart.astro
<astro-heart>
<button aria-label="Heart">💜</button> × <span>0</span>
</astro-heart>
<script>
class AstroHeart extends HTMLElement {
connectedCallback() {
let count = 0;
const heartButton = this.querySelector('button');
const countSpan = this.querySelector('span');
heartButton.addEventListener('click', () => {
count++;
countSpan.textContent = count.toString();
});
}
}
customElements.define('astro-heart', AstroHeart);
</script>

Преимущества этого подхода:

  1. Вы можете использовать this.querySelector(), чтобы искать элементы только внутри текущего экземпляра компонента.
  2. Метод connectedCallback() запускается браузером для каждого нового элемента на странице, что позволяет изолировать логику разных экземпляров.

Передача переменных из метаданных в скрипты

Заголовок раздела «Передача переменных из метаданных в скрипты»

Код в блоке метаданных (между ---) выполняется на сервере и недоступен в браузере. Чтобы передать данные в клиентский JavaScript, используйте data-* атрибуты.

src/components/AstroGreet.astro
---
const { message = 'Привет, мир!' } = Astro.props;
---
<astro-greet data-message={message}>
<button>Поздороваться</button>
</astro-greet>
<script>
class AstroGreet extends HTMLElement {
connectedCallback() {
const message = this.dataset.message;
const button = this.querySelector('button');
button.addEventListener('click', () => {
alert(message);
});
}
}
customElements.define('astro-greet', AstroGreet);
</script>