路由遮罩

路由掩码是一种掩盖路由的实际 URL 的方法,该 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 是什么。一个例子是 Devtools,我们在其中检测路由是否被掩码,并显示实际 URL 而不是掩码的 URL!

记住,你不需要担心这些。所有这些都将在后台自动为你处理!

如何使用路由掩码?

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

  • 命令式,通过 mask 选项,该选项在 <Link>navigate() API 中可用。
  • 声明式,通过 Router 的 routeMasks 选项。

在使用任一路由掩码 API 时,mask 选项接受与 <Link>navigate() API 接受的相同的导航对象。这意味着你可以使用与你已经熟悉的相同的 toreplacestatesearch 选项。唯一的区别是 mask 选项将用于掩盖正在导航到的路由的 URL。

🧠 mask 选项也是类型安全的!这意味着如果你正在使用 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,你还可以使用 Router 的 routeMasks 选项来声明式地掩盖路由。你不需要将 mask 选项传递给每个 <Link>navigate() 调用,而是可以在 Router 上创建一个路由掩码来掩盖匹配特定模式的路由。以下是与上面相同的路由掩码示例,但改用了 routeMasks 选项。

// 使用以下代码进行以下示例

tsx
import { createRouteMask } from '@tanstack/solid-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/solid-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 个选项,如果传入,它们将按优先级覆盖前一个选项:

  • 将 Router 的默认 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

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