框架
版本

路由遮罩

路由遮罩是一种遮罩实际 URL 的方式,该 URL 会保留在浏览器的历史记录和 URL 栏中。这对于以下场景非常有用:您希望显示与实际导航到的 URL 不同的 URL,然后在共享时(以及可选地在页面重新加载时)回退到显示的 URL。以下是一些示例:

  • 导航到模态路由,例如 /photo/5/modal,但将实际 URL 遮罩为 /photos/5
  • 导航到模态路由,例如 /post/5/comments,但将实际 URL 遮罩为 /posts/5
  • 导航到带有搜索参数 ?showLogin=true 的路由,但遮罩 URL 使其**不**包含搜索参数
  • 导航到带有搜索参数 ?modal=settings 的路由,但将 URL 遮罩为 `/settings`

这些场景都可以通过路由遮罩实现,甚至可以扩展以支持更高级的模式,例如并行路由

路由遮罩如何工作?

重要

您**无需**了解路由遮罩的工作原理即可使用它。本节适用于那些对内部工作原理感到好奇的人。跳到我如何使用路由遮罩?以了解如何使用它!

路由遮罩利用 location.state API 将所需的运行时位置存储在将写入 URL 的位置中。它将此运行时位置存储在 __tempLocation 状态属性下。

tsx
const location = {
  pathname: '/photos/5',
  search: '',
  hash: '',
  state: {
    key: 'wesdfs',
    __tempKey: 'sadfasd',
    __tempLocation: {
      pathname: '/photo/5/modal',
      search: '',
      hash: '',
      state: {},
    },
  },
}
const location = {
  pathname: '/photos/5',
  search: '',
  hash: '',
  state: {
    key: 'wesdfs',
    __tempKey: 'sadfasd',
    __tempLocation: {
      pathname: '/photo/5/modal',
      search: '',
      hash: '',
      state: {},
    },
  },
}

当路由器从历史记录中解析具有 location.state.__tempLocation 属性的位置时,它将使用该位置而不是从 URL 解析的位置。这允许您导航到像 /photos/5 这样的路由,并让路由器实际导航到 /photo/5/modal。发生这种情况时,历史记录位置将保存回 location.maskedLocation 属性中,以防我们需要知道**实际 URL** 是什么。一个使用此功能的示例是在开发工具中,我们检测路由是否被遮罩并显示实际 URL 而不是遮罩 URL!

请记住,您无需担心所有这些。所有这些都由系统在后台自动处理!

我如何使用路由遮罩?

路由遮罩是一个简单的 API,可以通过两种方式使用:

  • 通过 <Link>navigate() API 中可用的 mask 选项进行命令式操作
  • 通过路由器的 routeMasks 选项进行声明式操作

无论使用哪种路由遮罩 API,mask 选项都接受与 <Link>navigate() API 接受的导航对象相同的导航对象。这意味着您可以使用您已经熟悉的 toreplacestatesearch 选项。唯一的区别是 mask 选项将用于遮罩正在导航到的路由的 URL。

🧠 遮罩选项也**类型安全**!这意味着如果您正在使用 TypeScript,如果您尝试向 mask 选项传递无效的导航对象,您将收到类型错误。太棒了!

命令式路由遮罩

<Link>navigate() API 都接受一个 mask 选项,可用于遮罩正在导航的路由的 URL。这是一个使用 <Link> 组件的示例:

tsx
<Link
  to="/photos/$photoId/modal"
  params={{ photoId: 5 }}
  mask={{
    to: '/photos/$photoId',
    params: {
      photoId: 5,
    },
  }}
>
  Open Photo
</Link>
<Link
  to="/photos/$photoId/modal"
  params={{ photoId: 5 }}
  mask={{
    to: '/photos/$photoId',
    params: {
      photoId: 5,
    },
  }}
>
  Open Photo
</Link>

以下是使用 navigate() API 的示例

tsx
const navigate = useNavigate()

function onOpenPhoto() {
  navigate({
    to: '/photos/$photoId/modal',
    params: { photoId: 5 },
    mask: {
      to: '/photos/$photoId',
      params: {
        photoId: 5,
      },
    },
  })
}
const navigate = useNavigate()

function onOpenPhoto() {
  navigate({
    to: '/photos/$photoId/modal',
    params: { photoId: 5 },
    mask: {
      to: '/photos/$photoId',
      params: {
        photoId: 5,
      },
    },
  })
}

声明式路由遮罩

除了命令式 API,您还可以使用路由器的 routeMasks 选项来声明式地遮罩路由。无需将 mask 选项传递给每个 <Link>navigate() 调用,您可以改为在路由器上创建路由遮罩以遮罩符合特定模式的路由。以下是上述相同路由遮罩的示例,但使用 routeMasks 选项代替:

// 对于以下示例,请使用以下内容

tsx
import { createRouteMask } from '@tanstack/react-router'

const photoModalToPhotoMask = createRouteMask({
  routeTree,
  from: '/photos/$photoId/modal',
  to: '/photos/$photoId',
  params: (prev) => ({
    photoId: prev.photoId,
  }),
})

const router = createRouter({
  routeTree,
  routeMasks: [photoModalToPhotoMask],
})
import { createRouteMask } from '@tanstack/react-router'

const photoModalToPhotoMask = createRouteMask({
  routeTree,
  from: '/photos/$photoId/modal',
  to: '/photos/$photoId',
  params: (prev) => ({
    photoId: prev.photoId,
  }),
})

const router = createRouter({
  routeTree,
  routeMasks: [photoModalToPhotoMask],
})

创建路由遮罩时,您需要至少传递 1 个参数:

  • routeTree - 将应用路由遮罩的路由树
  • from - 路由遮罩将应用到的路由 ID
  • ...navigateOptions - <Link>navigate() API 接受的标准 tosearchparamsreplace 等选项

🧠 createRouteMask 选项也是**类型安全**的!这意味着如果您正在使用 TypeScript,如果您尝试向 routeMasks 选项传递无效的路由遮罩,您将收到类型错误。

分享 URL 时取消遮罩

URL 在共享时会自动取消遮罩,因为一旦 URL 从您的浏览器本地历史堆栈中分离,URL 遮罩数据就不再可用。本质上,一旦您从历史记录中复制并粘贴 URL,其遮罩数据就会丢失……毕竟,这就是遮罩 URL 的目的!

本地取消遮罩默认值

**默认情况下,当页面在本地重新加载时,URL 不会取消遮罩。** 遮罩数据存储在历史位置的 location.state 属性中,因此只要历史位置仍在您的历史堆栈内存中,遮罩数据将可用,并且 URL 将继续被遮罩。

页面重新加载时取消遮罩

如上所述,默认情况下,当页面重新加载时,URL 不会取消遮罩.

如果您希望在本地页面重新加载时取消遮罩 URL,您有 3 种选择,如果传入,每个选项都会覆盖前一个选项的优先级:

  • 将路由器的默认 unmaskOnReload 选项设置为 true
  • 使用 createRouteMask() 创建路由遮罩时,从遮罩函数返回 unmaskOnReload: true 选项
  • unmaskOnReload: true 选项传递给 <Link> 组件或 navigate() API
我们的合作伙伴
Code Rabbit
Netlify
Neon
Clerk
Convex
Sentry
订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。

订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。