视图过渡
本页内容

视图过渡



在您的 React Router 应用程序中使用 视图过渡 API,实现页面过渡之间的平滑动画。此功能允许您在客户端导航期间创建无缝的视觉过渡。

基本视图过渡

1. 在导航上启用视图过渡

启用视图过渡最简单的方法是在您的 LinkNavLinkForm 组件中添加 viewTransition 属性。这会自动将导航更新包装在 document.startViewTransition() 中。

<Link to="/about" viewTransition>
  About
</Link>

在没有任何额外 CSS 的情况下,这会在页面之间提供基本的交叉淡入淡出动画。

2. 通过编程式导航启用视图过渡

当使用 useNavigate 钩子进行编程式导航时,您可以通过传递 viewTransition: true 选项来启用视图过渡。

import { useNavigate } from "react-router";

function NavigationButton() {
  const navigate = useNavigate();

  return (
    <button
      onClick={() =>
        navigate("/about", { viewTransition: true })
      }
    >
      About
    </button>
  );
}

这提供了与在 Link 组件上使用 viewTransition 属性相同的交叉淡入淡出动画。

有关使用视图过渡 API 的更多信息,请参阅 Google Chrome 团队的《使用视图过渡 API 实现平滑过渡》指南

让我们构建一个图片库来演示如何触发和使用视图过渡。我们将创建一个图片列表,这些图片可以展开到带有平滑动画的详情视图。

import { NavLink } from "react-router";

export const images = [
  "https://remix.org.cn/blog-images/headers/the-future-is-now.jpg",
  "https://remix.org.cn/blog-images/headers/waterfall.jpg",
  "https://remix.org.cn/blog-images/headers/webpack.png",
  // ... more images ...
];

export default function ImageGalleryRoute() {
  return (
    <div className="image-list">
      <h1>Image List</h1>
      <div>
        {images.map((src, idx) => (
          <NavLink
            key={src}
            to={`/image/${idx}`}
            viewTransition // Enable view transitions for this link
          >
            <p>Image Number {idx}</p>
            <img
              className="max-w-full contain-layout"
              src={src}
            />
          </NavLink>
        ))}
      </div>
    </div>
  );
}

2. 添加过渡样式

为应在路由之间平滑过渡的元素定义视图过渡名称和动画。

/* Layout styles for the image grid */
.image-list > div {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: 10px;
}

.image-list h1 {
  font-size: 2rem;
  font-weight: 600;
}

.image-list img {
  max-width: 100%;
  contain: layout;
}

.image-list p {
  width: fit-content;
}

/* Assign transition names to elements during navigation */
.image-list a.transitioning img {
  view-transition-name: image-expand;
}

.image-list a.transitioning p {
  view-transition-name: image-title;
}

3. 创建图片详情路由

详情视图需要使用相同的视图过渡名称来创建无缝动画。

import { Link } from "react-router";
import { images } from "./home";
import type { Route } from "./+types/image-details";

export default function ImageDetailsRoute({
  params,
}: Route.ComponentProps) {
  return (
    <div className="image-detail">
      <Link to="/" viewTransition>
        Back
      </Link>
      <h1>Image Number {params.id}</h1>
      <img src={images[Number(params.id)]} />
    </div>
  );
}

4. 为详情视图添加匹配的过渡样式

/* Match transition names from the list view */
.image-detail h1 {
  font-size: 2rem;
  font-weight: 600;
  width: fit-content;
  view-transition-name: image-title;
}

.image-detail img {
  max-width: 100%;
  contain: layout;
  view-transition-name: image-expand;
}

高级用法

您可以使用渲染属性或 useViewTransitionState 钩子来更精确地控制视图过渡。

1. 使用渲染属性

<NavLink to={`/image/${idx}`} viewTransition>
  {({ isTransitioning }) => (
    <>
      <p
        style={{
          viewTransitionName: isTransitioning
            ? "image-title"
            : "none",
        }}
      >
        Image Number {idx}
      </p>
      <img
        src={src}
        style={{
          viewTransitionName: isTransitioning
            ? "image-expand"
            : "none",
        }}
      />
    </>
  )}
</NavLink>

2. 使用 useViewTransitionState 钩子

function NavImage(props: { src: string; idx: number }) {
  const href = `/image/${props.idx}`;
  // Hook provides transition state for specific route
  const isTransitioning = useViewTransitionState(href);

  return (
    <Link to={href} viewTransition>
      <p
        style={{
          viewTransitionName: isTransitioning
            ? "image-title"
            : "none",
        }}
      >
        Image Number {props.idx}
      </p>
      <img
        src={props.src}
        style={{
          viewTransitionName: isTransitioning
            ? "image-expand"
            : "none",
        }}
      />
    </Link>
  );
}
文档和示例 CC 4.0
编辑