Nuxt.js и AOS

Библиотека AOS используется для добавления анимаций при прокрутке страницы. В контексте Nuxt.js возникают особенности, связанные с серверным рендерингом (SSR), жизненным циклом компонентов и инициализацией клиентских библиотек.


Установка и подключение

Установка выполняется через пакетный менеджер:

npm install aos

или

yarn add aos

Подключение стилей:

import 'aos/dist/aos.css'

Особенности работы в Nuxt.js

AOS зависит от DOM, поэтому не может корректно выполняться на сервере. В Nuxt.js требуется:

  • инициализировать библиотеку только на клиенте
  • учитывать гидратацию
  • избегать вызовов в SSR-контексте

Способы подключения

1. Через плагин Nuxt

Создание файла plugins/aos.client.js:

import AOS from 'aos'
import 'aos/dist/aos.css'

export default defineNuxtPlugin(() => {
  return {
    provide: {
      aos: AOS
    }
  }
})

Файл имеет суффикс .client, что гарантирует выполнение только в браузере.


2. Регистрация в nuxt.config

export default defineNuxtConfig({
  plugins: [
    { src: '~/plugins/aos.client.js', mode: 'client' }
  ]
})

Инициализация AOS

Инициализация выполняется после монтирования:

<script setup>
import { onMounted } from 'vue'
import AOS from 'aos'

onMounted(() => {
  AOS.init({
    duration: 800,
    once: true
  })
})
</script>

Использование в шаблоне

Анимации задаются через data-атрибуты:

<div data-aos="fade-up">
  Контент
</div>

<div data-aos="zoom-in" data-aos-delay="200">
  Другой элемент
</div>

Обновление при динамическом контенте

В Nuxt часто используется динамическая подгрузка данных. После обновления DOM необходимо пересчитать позиции элементов:

AOS.refresh()

или

AOS.refreshHard()

Разница:

  • refresh — пересчёт без полной переинициализации
  • refreshHard — полная переработка DOM-элементов

Работа с маршрутизацией

При переходах между страницами в Nuxt (SPA-режим) анимации могут не срабатывать повторно. Решение — отслеживать смену маршрута:

import { useRouter } from 'vue-router'

const router = useRouter()

router.afterEach(() => {
  setTimeout(() => {
    AOS.refreshHard()
  }, 100)
})

Задержка необходима для завершения рендера.


Использование в layout

Инициализацию можно вынести в общий layout:

<script setup>
import { onMounted } from 'vue'
import AOS from 'aos'

onMounted(() => {
  AOS.init()
})
</script>

<template>
  <NuxtPage />
</template>

Конфигурация AOS

Основные параметры:

AOS.init({
  offset: 120,
  delay: 0,
  duration: 400,
  easing: 'ease',
  once: false,
  mirror: false,
  anchorPlacement: 'top-bottom'
})

Описание ключевых опций:

  • offset — расстояние до триггера анимации
  • delay — задержка перед началом
  • duration — длительность
  • once — запуск только один раз
  • mirror — повтор при прокрутке вверх
  • anchorPlacement — точка привязки

SSR и ошибки

Типичные ошибки:

Ошибка: window is not defined Причина: вызов AOS в серверном коде.

Решение:

  • использовать .client.js
  • вызывать только в onMounted

Оптимизация производительности

При большом количестве элементов:

  • ограничивать количество анимаций
  • использовать once: true
  • избегать сложных эффектов (например, flip + длительные duration)

Кастомные анимации

Можно создавать собственные анимации через CSS:

[data-aos="custom-fade"] {
  opacity: 0;
  transform: translateY(50px);
  transition: all 0.6s ease;
}

[data-aos="custom-fade"].aos-animate {
  opacity: 1;
  transform: translateY(0);
}

Использование:

<div data-aos="custom-fade">
  Элемент
</div>

Работа с компонентами

Если компонент появляется условно:

<div v-if="visible" data-aos="fade-in">
  Контент
</div>

После изменения visible:

watch(visible, () => {
  nextTick(() => {
    AOS.refresh()
  })
})

Интеграция с Composition API

Создание composable:

export function useAOS() {
  const initAOS = () => {
    AOS.init()
  }

  const refreshAOS = () => {
    AOS.refresh()
  }

  return { initAOS, refreshAOS }
}

Использование:

const { initAOS } = useAOS()

onMounted(() => {
  initAOS()
})

Lazy loading и AOS

При ленивой загрузке компонентов:

<ClientOnly>
  <LazyComponent />
</ClientOnly>

После загрузки:

onMounted(() => {
  setTimeout(() => {
    AOS.refresh()
  }, 200)
})

Совмещение с другими библиотеками

При использовании:

  • GSAP
  • Locomotive Scroll
  • Intersection Observer

важно избегать конфликтов скролла и событий.

Пример с кастомным скроллом:

scroll.on('scroll', () => {
  AOS.refresh()
})

Структурирование проекта

Рекомендуемая структура:

/plugins
  aos.client.js

/composables
  useAOS.js

/layouts
  default.vue

Частые проблемы

Анимации не запускаются:

  • отсутствует AOS.init()
  • забыты стили

Анимации срабатывают один раз:

  • включен once: true

Не работают после перехода:

  • отсутствует refreshHard

Практика использования

AOS в Nuxt.js наиболее эффективен для:

  • лендингов
  • маркетинговых страниц
  • презентаций
  • визуально насыщенных интерфейсов

В сложных приложениях с большим количеством интерактивных элементов предпочтительно использовать более гибкие решения, такие как Intersection Observer или специализированные анимационные библиотеки.