Пропустить до содержимого

Учебное пособие - Расширение с помощью анимации переходов

Анимации переходов — это способ управлять тем, что происходит, когда посетители переходят между страницами вашего сайта. API View Transitions в Astro позволяет добавлять дополнительные возможности навигации, включая плавные переходы и анимацию страниц, управление стопкой посещённых страниц в истории браузера и предотвращение обновления всей страницы, чтобы сохранить некоторые элементы и состояние страницы при обновлении отображаемого контента.

Приготовьтесь…

  • Импортировать и добавить маршрутизатор <ViewTransitions /> в общий элемент head
  • Добавить прослушиватели событий во время процесса навигации для запуска <script> при необходимости
  • Добавить анимации перехода между страницами с использованием директив перехода
  • Исключить из клиентской маршрутизации ссылку на отдельную страницу

Вам понадобится существующий проект Astro с общим базовым макетом или компонентом <Head />.

В этом уроке используется готовый проект Учебника по созданию блога, чтобы продемонстрировать добавление анимации переходов (маршрутизация на стороне клиента) в существующий проект Astro. Вы можете форкнуть и использовать эту кодовую базу локально или завершить учебник в браузере, отредактировав код учебника в блоге StackBlitz.

Вместо этого вы можете выполнить эти шаги в своем собственном проекте Astro, но вам нужно будет скорректировать инструкции с учётом вашей кодовой базы.

Мы рекомендуем использовать наш пример проекта для завершения этого краткого руководства. Затем вы сможете использовать полученные знания для создания анимации переходов в своем собственном проекте.

Из вводного руководства по созданию блога вы узнали о встроенной маршрутизации на основе файлов в Astro: Любой файл .astro, .md или .mdx, находящийся в папке src/pages/, автоматически становился новой страницей на вашем сайте.

Для навигации между этими страницами вы использовали стандартный элемент HTML <a>. Например, чтобы создать ссылку на страницу «О сайте», вы добавили строку <a href="/about/">О сайте</a> в заголовок страницы. Когда посетитель вашего сайта нажимал на эту ссылку, браузер обновлялся и загружал новую страницу с совершенно новым содержимым.

Полностраничная навигация против маршрутизации на стороне клиента (режим SPA)

Заголовок раздела Полностраничная навигация против маршрутизации на стороне клиента (режим SPA)

Когда браузер обновляет и загружает новую страницу, между старой и новой страницей нет никакой преемственности. При маршрутизации на стороне клиента новая страница отображается без полностраничного обновления браузера.

Маршрутизация на стороне клиента — это особенность сайтов с одностраничными приложениями (SPA), когда весь сайт или приложение представляет собой «одну страницу» JavaScript, содержимое которой обновляется в зависимости от взаимодействия с посетителем.

Поскольку каждая новая страница не требует полного обновления браузера, маршрутизация на стороне клиента позволяет управлять переходом между страницами несколькими способами. Постоянные элементы, такие как общий заголовок страницы, не обязательно полностью перерисовывать на экране. Переход от одной страницы к другой может выглядеть гораздо более плавным. Кроме того, можно сохранять состояние, что позволяет переносить значения с одной страницы на другую или даже воспроизводить видео, пока ваши посетители переходят по страницам!

Бывают случаи, когда вам нужно обновить браузер на всю страницу. Например, когда ссылка ведет посетителя на документ .pdf, браузеру необходимо загрузить эту новую страницу с сервера. Даже если в вашем проекте Astro включены анимации переходов, вы сможете указать, как браузер должен осуществлять навигацию как по умолчанию, так и по каждой ссылке, даже полностью отказаться от маршрутизации на стороне клиента.

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

  1. Добавление анимации переходов на мой астросайт…

  2. Что не является преимуществом анимации переходов Astro?

  3. Маршрутизатор анимации переходов…

Расширение учебника по блогам с помощью анимации переходов

Заголовок раздела Расширение учебника по блогам с помощью анимации переходов

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

  1. Обновите последнюю версию Astro и обновите все интеграции до их последних версий, выполнив следующие команды в терминале:

    Terminal window
    # Обновление до Astro v4.x
    npm install astro@latest
    # Пример: обновление интеграции с Preact
    npm install @astrojs/preact@latest
  1. Импортируйте и добавьте компонент <ViewTransitions /> в <head> макета вашей страницы.

    В учебном примере элемент <head> находится в файле src/layouts/BaseLayout.astro. Маршрутизатор ViewTransitions должен быть сначала импортирован в метаданных компонента. Затем добавьте компонент маршрутизации внутри элемента <head>.

    src/layouts/BaseLayout.astro
    ---
    import { ViewTransitions } from "astro:transitions";
    import Header from "../components/Header.astro";
    import Footer from "../components/Footer.astro";
    import "../styles/global.css";
    const { pageTitle } = Astro.props;
    ---
    <html lang="en">
    <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <meta name="generator" content={Astro.generator} />
    <title>{pageTitle}</title>
    <ViewTransitions />
    </head>
    <body>
    <Header />
    <h1>{pageTitle}</h1>
    <slot />
    <Footer />
    <script>
    import "../scripts/menu.js";
    </script>
    </body>
    </html>

    Для включения навигации Astro по умолчанию на стороне клиента не требуется никаких других настроек! Astro создаст анимацию страницы по умолчанию, основываясь на сходстве между старой и новой страницами, а также обеспечит обратное поведение для неподдерживаемых браузеров.

  2. Перемещайтесь между страницами в предварительном просмотре сайта.

    Просмотрите предварительный просмотр сайта на большом экране, например, в режиме рабочего стола. Перемещаясь между страницами сайта, обратите внимание, что содержимое старой страницы исчезает по мере того, как появляется содержимое новой. Используйте руководство об анимации переходов, чтобы добавить пользовательское поведение, если вас не устраивают настройки по умолчанию.

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

С анимацией переходов некоторые скрипты больше не могут повторно запускаться после перехода по странице, как это происходит при полностраничном обновлении браузера. Существует несколько событий во время маршрутизации на стороне клиента, которые вы можете прослушать, и вызвать события, когда они происходят. Теперь скрипты в вашем проекте должны подключаться к двум событиям, чтобы запускаться в нужное время во время навигации по странице: astro:page-load и astro:after-swap.

  1. Сделайте скрипт, управляющий компонентом мобильного меню <Hamburger />, доступным после перехода на новую страницу.

    Чтобы сделать мобильное меню интерактивным после перехода на новую страницу, добавьте следующий код, который прослушивает событие astro:page-load, возникающее в конце навигации по странице, и в ответ запускает существующий скрипт, чтобы меню гамбургера функционировало при нажатии:

    src/scripts/menu.js
    document.addEventListener('astro:page-load', () => {
    document.querySelector('.hamburger').addEventListener('click', () => {
    document.querySelector('.nav-links').classList.toggle('expanded');
    });
    });
  2. Сделайте скрипт, управляющий переключением цветовой темы, доступным после перехода по странице.

    В компоненте <ThemeIcon /> находится <script>, управляющий переключением светлой/тёмной темы. Чтобы переключение темы продолжало работать на каждой странице, удалите из скрипта атрибут is:inline и добавьте тот же слушатель событий, что и в предыдущем примере, чтобы событие astro:page-load могло вызвать вашу существующую функцию.

    Обновите существующий тег script, чтобы ваша функция запускалась в ответ на событие astro:page-load, делая тему интерактивной после того, как новая страница полностью загрузится и станет видимой для пользователя:

    src/components/ThemeIcon.astro
    ---
    ---
    <button id="themeToggle"> /* ... */ </button>
    <style> /* ... */ </style>
    <script is:inline>
    document.addEventListener('astro:page-load', () => {
    const theme = (() => {
    if (typeof localStorage !== "undefined" && localStorage.getItem("theme")) {
    return localStorage.getItem("theme");
    }
    if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
    return "dark";
    }
    return "light";
    })();
    if (theme === "light") {
    document.documentElement.classList.remove("dark");
    } else {
    document.documentElement.classList.add("dark");
    }
    window.localStorage.setItem("theme", theme);
    const handleToggleClick = () => {
    const element = document.documentElement;
    element.classList.toggle("dark");
    const isDark = element.classList.contains("dark");
    localStorage.setItem("theme", isDark ? "dark" : "light");
    };
    document
    .getElementById("themeToggle")
    .addEventListener("click", handleToggleClick);
    });
    </script>

    Теперь при использовании маршрутизатора <ViewTransitions /> переключение темы происходит интерактивно на каждой странице после завершения её загрузки.

  3. Проверьте наличие темы для предотвращения мигания в тёмном режиме.

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

    Чтобы проверить наличие и при необходимости установить тёмный режим на более ранних этапах навигации, создайте функцию, которая будет запускаться в ответ на событие astro:after-swap. Следующая функция для проверки localStorage браузера на наличие тёмной темы будет выполняться сразу же после того, как новая страница заменит старую, до того, как элементы DOM будут выведены на экран.

    Добавьте этот новый скрипт в компонент <ThemeIcon />, в дополнение к скрипту, управляющему переключением темы.

    src/components/ThemeIcon.astro
    <script> ... </script>
    <script>
    document.addEventListener('astro:after-swap', () => {
    localStorage.theme === 'dark'
    ? document.documentElement.classList.add("dark")
    : document.documentElement.classList.remove("dark");
    });
    </script>

Теперь каждое изменение страницы, использующее маршрутизатор <ViewTransitions /> для навигации на стороне клиента (и, соответственно, доступ к событию astro:after-swap), сможет определить theme: dark из localStorage браузера и соответствующим образом обновляет текущую страницу, прежде чем она будет отображена для зрителя.

Каков правильный порядок событий после того, как посетитель нажимает на ссылку для перехода на новую страницу во время навигации на стороне клиента?

  1. Измените стандартную анимацию fade на lide для заголовка страницы.

    При включенных переходах между страницами для всех анимаций перехода между страницами установлено небольшое затухание. Astro также предоставляет встроенную анимацию slide. Чтобы изменить тип анимации для отдельного элемента, добавьте директиву transition:animate="".

    Например, чтобы заголовки страниц не исчезали, а скользили, добавьте transition:animate="slide" к элементу <h1> в BaseLayout:

    src/layouts/BaseLayout.astro
    ---
    import Header from "../components/Header.astro";
    import Footer from "../components/Footer.astro";
    import "../styles/global.css";
    import { ViewTransitions } from "astro:transitions";
    const { pageTitle } = Astro.props;
    ---
    <html lang="en">
    <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <meta name="generator" content={Astro.generator} />
    <title>{pageTitle}</title>
    <ViewTransitions />
    </head>
    <body>
    <Header />
    <h1 transition:animate="slide">{pageTitle}</h1>
    <slot />
    <Footer />
    <script>
    import "../scripts/menu.js";
    </script>
    </body>
    </html>

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

Попробуйте сами — сделайте навигационные ссылки скользящими

Заголовок раздела Попробуйте сами — сделайте навигационные ссылки скользящими

Добавьте директиву анимации, чтобы <div> в Navigation.astro, содержащий все ссылки заголовков, скользил при постраничной навигации, следуя тем же шагам, что и выше.

Покажите мне код.
src/components/Navigation.astro
---
---
<div transition:animate="slide" class="nav-links">
<a href="/">Главная</a>
<a href="/about/">О сайте</a>
<a href="/blog/">Блог</a>
<a href="/tags/">Теги</a>
</div>

Проверьте предварительный просмотр в браузере: теперь ссылки на название страницы и заголовок будут появляться на каждой странице навигации.

  1. Добавьте более длительное затухание для описаний записей в блоге.

    Вы также можете настроить встроенные анимации Astro, импортировав их, а затем указав любые свойства анимации CSS.

    Например, чтобы описание медленно исчезало при переходе к записи в блоге, импортируйте анимацию fade в макет для записей блога в формате Markdown. Затем добавьте директиву перехода для fade от Astro с длительностью 2s:

    src/layouts/MarkdownPostLayout.astro
    ---
    import BaseLayout from "./BaseLayout.astro";
    import { fade } from "astro:transitions";
    const { frontmatter } = Astro.props;
    ---
    <BaseLayout pageTitle={frontmatter.title}>
    <p>{frontmatter.pubDate.slice(0, 10)}</p>
    <p transition:animate={fade({ duration: '2s' })} ><em>{frontmatter.description}</em></p>
    <p>Автор: {frontmatter.author}</p>
    <img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} />
    <slot />
    </BaseLayout>

    Перейдите к любой записи блога в предварительном просмотре браузера, и вы увидите, что описание исчезает медленнее, чем остальной текст.

Принудительная полная перезагрузка браузера для некоторых ссылок

Заголовок раздела Принудительная полная перезагрузка браузера для некоторых ссылок
  1. Предотвратите маршрутизацию на стороне клиента и вместо этого требуйте перезагрузки браузера при переходе на страницу «О сайте».

    Иногда требуется полная перезагрузка браузера при нажатии посетителем определённой ссылки. Например, вы можете ссылаться на страницу, которая также не использует маршрутизатор <ViewTransitions />, или на файл напрямую, например .pdf.

    Чтобы браузер обновлялся каждый раз, когда вы нажимаете на навигационную ссылку, чтобы перейти на страницу «О сайте», добавьте атрибут data-astro-reload к тегу <a> в компоненте <Navigation />. Это полностью переопределит маршрутизатор <ViewTransitions /> и все анимации переходов для этой одной ссылки.

    src/components/Navigation.astro
    ---
    ---
    <div transition:animate="slide" class="nav-links">
    <a href="/">Главная</a>
    <a href="/about/" data-astro-reload>О сайте</a>
    <a href="/blog/">Блог</a>
    <a href="/tags/">Теги</a>
    </div>

    Теперь, когда вы нажимаете навигационную ссылку на страницу «О сайте», анимации не будет. Ссылки и заголовок страницы не будут скользить, а содержимое страницы не будет исчезать, если вы перейдете на страницу «О сайте» по этой ссылке.

  2. Добавьте ссылку на страницу «О сайте» из имени автора в макет Markdown для записей блога.

    data-astro-reload вызывает полное обновление браузера только при переходе на новую страницу из ссылки, к которой она добавлена. Он не контролирует все случаи перехода на страницу «О сайте».

    В компоненте <MarkdownPostLayout /> добавьте ссылку на страницу «О сайте» в имени автора:

    src/layouts/MarkdownPostLayout.astro
    ---
    import BaseLayout from "./BaseLayout.astro";
    import { fade } from "astro:transitions";
    const { frontmatter } = Astro.props;
    ---
    <BaseLayout pageTitle={frontmatter.title}>
    <p>{frontmatter.pubDate.slice(0, 10)}</p>
    <p transition:animate={fade({ duration: '2s' })} ><em>{frontmatter.description}</em></p>
    <p>Автор: <a href="/about/">{frontmatter.author}</a></p>
    <img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} />
    <slot />
    </BaseLayout>

Если вы посетите любую запись блога в предварительном просмотре браузера, а затем щёлкните по имени автора, чтобы перейти на страницу «О сайте», как будет выглядеть навигация по странице?

Когда посетитель переходит по ссылке на страницу «О сайте» из отдельной записи блога, ссылки на заголовок страницы и навигационный заголовок , поскольку

Ещё столько всего предстоит исследовать! Смотрите наше полное руководство, чтобы узнать, что ещё можно сделать с помощью анимации переходов.

Полный пример использования анимации переходов в блоге смотрите в ветке View Transitions репозитория учебника.