Библиотека AOS используется для добавления анимаций при прокрутке страницы. В контексте Nuxt.js возникают особенности, связанные с серверным рендерингом (SSR), жизненным циклом компонентов и инициализацией клиентских библиотек.
Установка выполняется через пакетный менеджер:
npm install aos
или
yarn add aos
Подключение стилей:
import 'aos/dist/aos.css'
AOS зависит от DOM, поэтому не может корректно выполняться на сервере. В Nuxt.js требуется:
Создание файла plugins/aos.client.js:
import AOS from 'aos'
import 'aos/dist/aos.css'
export default defineNuxtPlugin(() => {
return {
provide: {
aos: AOS
}
}
})
Файл имеет суффикс .client, что гарантирует выполнение
только в браузере.
export default defineNuxtConfig({
plugins: [
{ src: '~/plugins/aos.client.js', mode: 'client' }
]
})
Инициализация выполняется после монтирования:
<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:
<script setup>
import { onMounted } from 'vue'
import AOS from 'aos'
onMounted(() => {
AOS.init()
})
</script>
<template>
<NuxtPage />
</template>
Основные параметры:
AOS.init({
offset: 120,
delay: 0,
duration: 400,
easing: 'ease',
once: false,
mirror: false,
anchorPlacement: 'top-bottom'
})
Описание ключевых опций:
Типичные ошибки:
Ошибка: window is not defined Причина:
вызов AOS в серверном коде.
Решение:
.client.jsonMountedПри большом количестве элементов:
once: trueflip + длительные
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()
})
})
Создание composable:
export function useAOS() {
const initAOS = () => {
AOS.init()
}
const refreshAOS = () => {
AOS.refresh()
}
return { initAOS, refreshAOS }
}
Использование:
const { initAOS } = useAOS()
onMounted(() => {
initAOS()
})
При ленивой загрузке компонентов:
<ClientOnly>
<LazyComponent />
</ClientOnly>
После загрузки:
onMounted(() => {
setTimeout(() => {
AOS.refresh()
}, 200)
})
При использовании:
важно избегать конфликтов скролла и событий.
Пример с кастомным скроллом:
scroll.on('scroll', () => {
AOS.refresh()
})
Рекомендуемая структура:
/plugins
aos.client.js
/composables
useAOS.js
/layouts
default.vue
Анимации не запускаются:
AOS.init()Анимации срабатывают один раз:
once: trueНе работают после перехода:
refreshHardAOS в Nuxt.js наиболее эффективен для:
В сложных приложениях с большим количеством интерактивных элементов предпочтительно использовать более гибкие решения, такие как Intersection Observer или специализированные анимационные библиотеки.