Skip to content

教程 - 通过视图转场进行扩展

视图转换是一种控制访问者在你网站的页面之间导航时发生的情况的方法。Astro 的视图转换 API 允许你添加可选的导航功能,包括平滑的页面转换和动画、控制浏览器访问页面的历史堆栈以及防止全页面刷新,以便在更新显示的内容时保留某些页面元素和状态。

¥View transitions are a way to control what happens when visitors navigate between pages on your site. Astro’s View Transitions API allows you to add optional navigation features including smooth page transitions and animations, controlling the browser’s history stack of visited pages, and preventing full-page refreshes in order to persist some page elements and state while updating the content displayed.

Get ready to…

  • <ViewTransitions /> 路由导入并添加到公共 head 元素

  • 在导航过程中添加事件监听器,以便在需要时触发 <script>

  • 使用过渡指令添加页面过渡动画

  • 选择退出单个页面链接的客户端路由

¥Prerequisites

你将需要一个具有通用基本布局或 <Head /> 组件的现有 Astro 项目。

¥You will need an existing Astro project with a common base layout or <Head /> component.

本教程使用 构建博客教程的完成项目 演示向现有 Astro 项目添加视图转换(客户端路由)。你可以在本地分叉并使用该代码库,或者在 在 StackBlitz 中编辑博客教程的代码 之前在浏览器中完成本教程。

¥This tutorial uses the Build a Blog tutorial’s finished project to demonstrate adding view transitions (client-side routing) to an existing Astro project. You can fork and use that codebase locally, or complete the tutorial in the browser by editing the blog tutorial’s code in StackBlitz.

你可以在自己的 Astro 项目中遵循这些步骤,但你需要调整代码库的说明。

¥You can instead follow these steps with your own Astro project, but you will need to adjust the instructions for your codebase.

我们建议首先使用我们的示例项目来完成这个简短的教程。然后,你可以使用所学知识在自己的项目中创建视图过渡。

¥We recommend using our sample project to complete this short tutorial first. Then, you can use what you have learned to create view transitions in your own project.

¥Build a Blog Tutorial Code

建立博客入门教程 中,你了解了 Astro 的 内置基于文件的路由src/pages/ 文件夹中任何位置的任何 .astro.md.mdx 文件都会自动成为你网站上的新页面。

¥In the Build a Blog introductory tutorial, you learned about Astro’s built-in file-based routing: any .astro, .md, or .mdx file anywhere within the src/pages/ folder automatically became a new page on your site.

要在这些页面之间导航,你使用了标准 HTML <a> 元素。例如,要创建指向“关于”页面的链接,你将 <a href="/about/">About</a> 添加到页面标题中。当你网站的访问者单击该链接时,浏览器会刷新并加载包含全新内容的新页面。

¥To navigate between these pages, you used the standard HTML <a> element. For example, to create a link to your About page, you added <a href="/about/">About</a> to your page header. When a visitor to your site clicked that link, the browser refreshed and loaded a new page with entirely new content.

全页导航与客户端路由(SPA 模式)

Section titled 全页导航与客户端路由(SPA 模式)

¥Full-page navigation vs client-side routing (SPA mode)

当浏览器刷新并加载新页面时,旧页面和新页面之间不存在连续性。在客户端路由期间,将显示新页面而无需刷新整个页面浏览器。

¥When a browser refreshes and loads a new page, there is no continuity between the old page and the new page. During client-side routing, a new page is displayed without a full-page browser refresh.

客户端路由是单页应用 (SPA) 网站的一项功能,其中你的整个网站或应用都是 “一页” 的 JavaScript,其内容根据访问者交互进行更新。

¥Client-side routing is a feature of single-page application (SPA) sites, where your entire site or app is “one page” of JavaScript whose content is updated based on visitor interaction.

由于每个新页面不需要完全刷新浏览器,因此客户端路由允许你通过多种方式控制页面转换。持久元素(例如通用页面标题)不必在屏幕上完全重新渲染。从一个页面到另一页面的过渡会显得更加平滑。而且,状态可以被保留,允许你将值从一个页面转移到下一个页面,甚至可以在访问者浏览页面时保持视频播放!

¥Because each new page does not require a full browser refresh, client-side routing allows you to control page transitions in several ways. Persistent elements, such as a common page header, do not have to be entirely rerendered on the screen. The transition from one page to another can appear much smoother. And, state can be preserved, allowing you to transfer values from one page to the next, or even keep a video playing as your visitors navigate pages!

有时你会想要或需要刷新整页浏览器。例如,当访问者通过链接访问 .pdf 文档时,你将需要浏览器从服务器加载该新页面。即使在 Astro 项目中启用了视图转换,你也可以指定浏览器在默认情况下和基于每个链接的导航方式,甚至完全选择退出客户端路由。

¥There are times when you will want or need a full-page browser refresh. For example, when a link takes a visitor to a .pdf document, you will need the browser to load that new page from the server. Even with view transitions enabled in your Astro project, you will be able to specify how the browser should navigate both by default and on a per-link basis, even opting out of client-side routing entirely.

在我们的指南中阅读有关 Astro 的视图转换 的更多信息,或深入了解以下说明以使用视图转换扩展博客。

¥Read more about Astro’s view transitions in our guide, or dive into the instructions below to extend the blog with view transitions.

¥Test your knowledge

  1. 将视图转换添加到我的 astro 网站…
  1. 以下哪个不是 Astro 视图转换的好处?
  1. 视图转换路由…

通过视图转场扩展博客教程

Section titled 通过视图转场扩展博客教程

¥Extending the blog tutorial with view transitions

以下步骤向你展示如何通过添加客户端路由来增强页面转换来扩展构建博客教程的最终产品。

¥The steps below show you how to extend the final product of the Build a Blog tutorial by adding client-side routing to enhance page transitions.

¥Upgrade dependencies

  1. Upgrade to the latest version of Astro, and upgrade all integrations to their latest versions by running the following commands in your terminal:

    Terminal window
    # Upgrade to Astro v4.x
    npm install astro@latest
    # Example: upgrade the blog tutorial Preact integration
    npm install @astrojs/preact@latest

¥Add the <ViewTransitions /> router

  1. Import and add the <ViewTransitions /> component to the <head> of your page layout.

    In the Blog tutorial example, the <head> element is found in src/layouts/BaseLayout.astro. The ViewTransitions router must be first imported into the component’s frontmatter. Then, add the routing component inside the <head> element.

    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>

    No other configuration is necessary to enable Astro’s default client-side navigation! Astro will create default page animations based on the similarities between the old and new page, and will also provide fallback behavior for unsupported browsers.

  2. Navigate between pages in your site preview.

    View your site preview at a large screen size, such as desktop mode. As you move between pages on your site, notice that the old page content appears to fade out as the new page content fades in. Use the view transitions guide to add custom behavior if you are not satisfied with the defaults.

    View your site preview at a smaller screen size, and try to use the hamburger menu to navigate between pages. Notice that your menu will no longer work after the first page load.

¥Update scripts

通过视图转换,某些脚本可能不再像全页浏览器刷新那样在页面导航后重新运行。有几种 你可以监听的客户端路由期间的事件,并在发生时触发事件。现在,项目中的脚本需要挂接到两个事件,以便在页面导航期间在正确的时间运行:astro:page-loadastro:after-swap

¥With view transitions, some scripts may no longer re-run after page navigation like they do with full-page browser refreshes. There are several events during client-side routing that you can listen for, and fire events when they occur. The scripts in your project will now need to hook into two events to run at the right time during page navigation: astro:page-load and astro:after-swap.

  1. Make the script controlling the <Hamburger /> mobile menu component available after navigating to a new page.

    To make your mobile menu interactive after navigating to a new page, add the following code that listens for the astro:page-load event which runs at the end of page navigation, and in response, runs the existing script to make the hamburger menu function when clicked:

    src/scripts/menu.js
    document.addEventListener('astro:page-load', () => {
    document.querySelector('.hamburger').addEventListener('click', () => {
    document.querySelector('.nav-links').classList.toggle('expanded');
    });
    });
  2. Make the script controlling the theme toggle available after page navigation.

    The <script> that controls the light/dark theme toggle is located in the <ThemeIcon /> component. For the theme toggle to continue to function on every page, remove the is:inline attribute from the script and add the same event listener as in the previous example so that astro:page-load event can trigger your existing function.

    Update the existing script tag so that your function runs in response to the astro:page-load event, making your theme toggle interactive after the new page is fully loaded and visible to the user:

    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").onclick = handleToggleClick;
    });
    </script>

    Now, the theme toggle is interactive on every page when using the <ViewTransitions /> router, after the page has finished loading.

  3. Check for theme earlier to prevent flashing in dark mode.

    The theme toggle works on every page, but its script is loaded at the end of the navigation process, after the new page has fully loaded in the browser. There may be a flash of the light theme version of the site before this theme toggle script runs and checks which theme it should use on the page.

    To check for, and if necessary set, dark mode earlier in the navigation process, create a function that will run in response to the astro:after-swap event. The following function to check the browser’s localStorage for dark theme will run when the first page is visited and immediately after the new page has replaced the old page, before the DOM elements are painted to the screen.

    Add this new script to the <ThemeIcon /> component, in addition to the script that controls the theme toggle.

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

现在,每个使用 <ViewTransitions /> 路由进行客户端导航(并因此访问 astro:after-swap 事件)的页面更改都将能够从浏览器的 localStorage 中检测到 theme: dark,并在页面渲染给查看者之前相应地更新当前页面。

¥Now, every page change that uses the <ViewTransitions /> router for client-side navigation (and therefore access to the astro:after-swap event) will be able to detect theme: dark from the browser’s localStorage and update the current page accordingly before the page is rendered for the viewer.

¥Test your knowledge

在客户端导航期间,访问者单击链接转到新页面后,正确的事件顺序是什么?

¥Which is the correct order of events after a visitor clicks a link to go to a new page during client-side navigation?

¥Customize Transition animations

  1. Change the default fade animation to a slide for the page title.

    With view transitions enabled, you currently have a small fade in and out set for all page transition animations. Astro also provides a built-in slide animation. To change the type of animation for a single element, add the transition:animate="" directive.

    For example, to make the page titles slide in instead of fade in, add transition:animate="slide" to the <h1> element in the 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>

在浏览器预览中,你现在将看到页面标题滑到屏幕上,而正文等其他元素则继续淡入和淡出。

¥In your browser preview, you will now see the page titles slide on to the screen, while other elements such as the body text continues to fade in and out.

自己尝试一下 - 使导航链接滑入

Section titled 自己尝试一下 - 使导航链接滑入

¥Try it yourself - Make the navigation links slide in

添加动画指令,使包含所有标题链接的 Navigation.astro 中的 <div> 滑入页面导航中,紧随 与上面相同的步骤

¥Add an animation directive to make the <div> in Navigation.astro containing all the header links slide in on page navigation, following the same steps as above.

Show me the code.
src/components/Navigation.astro
---
---
<div transition:animate="slide" class="nav-links">
<a href="/">Home</a>
<a href="/about/">About</a>
<a href="/blog/">Blog</a>
<a href="/tags/" >Tags</a>
</div>

检查浏览器预览,现在页面标题和标题链接都将滑入每个页面导航中。

¥Check your browser preview and now both the page title and the header links will slide in on every page navigation.

  1. Add a longer fade-in on your blog post descriptions.

    You can also customize Astro’s built-in animations by importing them, then providing any CSS animation properties.

    For example, to make the description fade in slowly when you navigate to a blog post, import the fade animation in your layout for Markdown blog posts. Then, add the transition directive for Astro’s fade with a duration of 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>Written by: {frontmatter.author}</p>
    <img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} />
    <slot />
    </BaseLayout>

    Navigate to any blog post in your browser preview, and you will see the description fade in slower than the rest of the text.

    Read more about the different transition directives and customizing animations.

强制某些链接完全重新加载浏览器

Section titled 强制某些链接完全重新加载浏览器

¥Force a full browser reload for some links

  1. Prevent client-side routing and instead require the browser to reload when navigating to your About page.

    Sometimes you will want a full browser reload when visitors click a certain link. For example, you may be linking to a page that does not also use the <ViewTransitions /> router, or to a file directly such as a .pdf.

    To make it so that your browser refreshes every time you click the navigation link to go to your About page, add the data-astro-reload attribute to the <a> tag in your <Navigation /> component. This will override the <ViewTransitions /> router entirely, and any of the view transition animations, for this one link.

    src/components/Navigation.astro
    ---
    ---
    <div transition:animate="slide" class="nav-links">
    <a href="/">Home</a>
    <a href="/about/" data-astro-reload>About</a>
    <a href="/blog/">Blog</a>
    <a href="/tags/">Tags</a>
    </div>

    Now, when you click the navigation link to your About page, no animations will occur. The page links and title will not slide in, and the page content will not fade in when you navigate to your About page using this link.

  2. Add a link to your About page from your author name in your Markdown layout for blog posts.

    data-astro-reload only triggers a full browser refresh when going to a new page from the link it is added to. It does not control all instances of navigating to your About page.

    In your <MarkdownPostLayout /> component, add a link to your About page on your author name:

    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>Written by: <a href="/about/">{frontmatter.author}</a></p>
    <img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} />
    <slot />
    </BaseLayout>

如果你在浏览器预览中访问任何博客文章,然后单击链接的作者名称以转到“关于”页面,页面导航会是什么样子?

¥If you visit any blog post in your browser preview, and then click on the linked author name to be taken to the About page, what does the page navigation look like?

当访问者从单个博客文章点击“关于”页面的链接时,页面标题和标题导航链接 ,因为

¥When a visitor clicks a link to the About page from an individual blog post, the page title and header navigation links because

还有很多东西需要探索!请参阅我们的 完整的视图转换指南,了解你可以通过视图转换执行的更多操作。

¥There is still so much more to explore! See our full View Transitions Guide for more things you can do with view transitions.

有关使用视图转换的博客教程的完整示例,请参阅教程存储库的 查看转换分支

¥For the full example of the blog tutorial using view transitions, see the View Transitions branch of the tutorial repo.

Astro 中文网 - 粤ICP备13048890号