F FisherHub Docs

04. 进阶模式

View Transitions API

Astro 内置了 View Transitions API 支持,让多页面应用(MPA)获得类似单页面应用(SPA)的平滑过渡动画。全局启用只需要在 <head> 中添加一个标签:

---
// src/layouts/DocLayout.astro
import { ViewTransitions } from 'astro:transitions'
---

<html lang="zh-CN">
  <head>
    <ViewTransitions />
    <!-- 其他 head 内容 -->
  </head>
  <body>
    <slot />
  </body>
</html>

启用后,站内导航会触发页面过渡动画,而不是硬刷新。

自定义过渡动画

可以为特定元素指定过渡名称,实现元素级别的动画:

---
// src/pages/index.astro
import { transition } from 'astro:transitions'
---

<h1 transition:name="page-title">首页</h1>
<img
  src="/hero.jpg"
  transition:name="hero-image"
  alt="Hero"
/>

当两个页面拥有相同 transition:name 的元素时,Astro 会自动执行 DOM 元素的平滑过渡(morph),而不是整个页面的替换。

过渡指令

Astro 提供了多个 transition:* 指令控制动画行为:

<nav transition:persist="nav-menu">
  <!-- 这个元素在页面切换时保持状态,不会重新渲染 -->
</nav>

<div transition:animate="slide">
  <!-- 使用预设的滑动动画 -->
</div>

可用的动画预设:fadeslidemorphinitialnone

Islands 架构

Astro 的 Islands 架构是其核心性能优势。默认情况下,组件只在构建时渲染为静态 HTML。使用 Client Directives 可以精确控制哪些组件需要客户端 JavaScript。

Client Directives 详解

---
import InteractiveCounter from '../components/InteractiveCounter'
import HeavyChart from '../components/HeavyChart'
import LazyMap from '../components/LazyMap'
import BlogComment from '../components/BlogComment'
---

<!-- 页面加载时立即水合 -->
<InteractiveCounter client:load />

<!-- 元素进入视口时水合(懒加载) -->
<HeavyChart client:visible />

<!-- 浏览器空闲时水合(低优先级) -->
<LazyMap client:idle />

<!-- HTML 只与当前元素交互时水合 -->
<BlogComment client:only="react" />

各指令的适用场景:

指令时机适用场景
client:load页面加载立即执行导航栏、搜索框、需要立即交互的元素
client:idle浏览器 requestIdleCallback分析图表、非关键 UI
client:visible元素进入视口长页面下方的评论区、图片轮播
client:media匹配媒体查询响应式组件
client:only仅客户端渲染依赖浏览器 API 的组件

组合使用示例

---
// src/pages/dashboard.astro
import Sidebar from '../components/Sidebar.astro'
import RealtimeChart from '../components/RealtimeChart'
import NotificationToast from '../components/NotificationToast'
---

<Sidebar />
<main>
  <article>
    <!-- 静态内容,零 JS -->
    <h1>仪表盘</h1>
    <p>欢迎回来!这是你的数据概览。</p>
  </article>

  <!-- 仅图表部分需要 JS -->
  <RealtimeChart client:visible />

  <!-- 轻量级交互 -->
  <NotificationToast client:load />
</main>

这样设计的结果是:页面主体是纯 HTML,只有 RealtimeChartNotificationToast 会加载少量 JS,页面整体性能远高于全 SPA 方案。

图片优化

Astro 内置的 ImagePicture 组件提供自动优化:

---
import { Image, Picture } from 'astro:assets'
import heroImage from '../assets/hero.jpg'
---

<!-- 自动生成 WebP/AVIF 格式、调整尺寸、懒加载 -->
<Image
  src={heroImage}
  alt="Banner 图片"
  width={1200}
  height={630}
  format="avif"
  loading="lazy"
  decoding="async"
/>

<!-- 响应式图片:不同视口输出不同的分辨率 -->
<Picture
  src={heroImage}
  formats={['avif', 'webp', 'jpg']}
  widths={[480, 768, 1200]}
  sizes="(max-width: 768px) 100vw, 1200px"
  alt="响应式 Banner"
/>

Image 组件的优化能力:

  • 自动转换为 WebP / AVIF 等现代格式
  • 生成多分辨率源文件
  • 内置懒加载(loading="lazy"
  • 防止布局偏移(自动注入宽高属性)

对于 public/ 目录中的外部图片,可以手动使用 getImage() 工具函数:

---
import { getImage } from 'astro:assets'

const optimized = await getImage({
  src: '/external-photo.jpg',
  width: 800,
  quality: 80,
})
---

<img src={optimized.src} width={optimized.width} height={optimized.height} alt="" />

性能审计

使用浏览器 DevTools 的 Lighthouse 面板对站点进行性能审计。以下是 Astro 项目的常见优化目标:

核心 Web 指标

指标含义Astro 的优势
LCP最大内容绘制Astro 的零 JS 默认让 LCP 极低
INP首次交互延迟仅水合必要的岛屿,INP 大幅优化
CLS累积布局偏移Image 组件自动设宽高,避免布局偏移

常见优化措施

1. 预加载关键资源

<head>
  <!-- 预加载字体 -->
  <link rel="preload" href="/fonts/inter-var.woff2" as="font" crossorigin />

  <!-- 预连接第三方源 -->
  <link rel="preconnect" href="https://fonts.googleapis.com" />
</head>

2. 压缩图片

构建时自动压缩 SVG 和图片:

// astro.config.mjs
import { defineConfig } from 'astro/config'

export default defineConfig({
  image: {
    service: {
      // 使用内置的 Sharp 图片处理服务
      entrypoint: 'astro/assets/services/sharp',
      config: {
        quality: 80,
      },
    },
  },
})

3. 分析 bundle 大小

# 构建时输出组件大小分析报告
bunx astro build

查看 dist/ 目录,确认每个页面只包含必要的 JS 文件。

Sitemap 生成

使用 @astrojs/sitemap 集成自动生成 sitemap.xml

bun add @astrojs/sitemap

astro.config.mjs 中配置:

import { defineConfig } from 'astro/config'
import sitemap from '@astrojs/sitemap'

export default defineConfig({
  site: 'https://docs.example.com',
  integrations: [
    sitemap({
      // 自定义过滤规则
      filter: (page) =>
        !page.includes('/admin') &&
        !page.includes('/draft'),

      // 自定义每项属性
      entryLimit: 50000,

      // 自定义 changefreq
      changefreq: 'weekly',
      priority: 0.7,

      // 配置多语言替代 URL
      serialize: (item) => ({
        ...item,
        links: [
          { lang: 'zh-CN', url: `https://docs.example.com/zh${item.url}` },
          { lang: 'en', url: `https://docs.example.com/en${item.url}` },
        ],
      }),
    }),
  ],
})

构建后访问 https://docs.example.com/sitemap-index.xml 查看生成的站点地图。确保 site 配置正确,否则 Sitemap 的 URL 会是空的。