前言

在开发 Web 应用时,我们经常需要在页面跳转时传递一些数据。例如:

  • 点击用户列表项,跳转到用户详情页,并携带用户 ID
  • 搜索页面跳转,并附带查询条件

很多开发者只熟悉查询参数?key=value) 和动态路由/user/:id) 两种方式,但其实还有第三种更灵活的方式:隐式传参state

本文将详细介绍这三种传参方式,并深入解析它们的底层实现原理

动态路由传参(Dynamic Routing)

适用场景

  • 需要 SEO 友好的 URL(如 /product/123
  • 参数是永久性的(如用户 ID、文章 ID)

React Router 示例

// 路由配置
<Route path="/user/:id" element={<UserPage />} />

// 跳转(传递参数)
navigate("/user/123");

// 获取参数
const { id } = useParams(); // id = "123"

Vue Router 示例

// 路由配置
{ path: "/user/:id", component: UserPage }

// 跳转(传递参数)
router.push("/user/123");

// 获取参数
const { id } = useRoute().params; // id = "123"

原理

动态路由的底层是 URL 路径匹配

  1. 浏览器发送请求时,服务器或前端路由(如 vue-router)解析 URL,提取 :id 部分
  2. 在 SPA 中,路由库(如 history)会监听 URL 变化,当访问 /user/123 时,不会真正发送 GET 请求,而是匹配相应组件并渲染

特点

  • 参数在 URL 中可见,适合 SEO 和分享
  • 只能传递字符串,不能传复杂对象

查询参数传参(Query Parameters)

适用场景

  • 需要筛选、搜索、分页(如 /search?q=kito&page=1
  • 参数是可选的(如排序方式、过滤条件)

React Router 示例

// 跳转(传递参数)
navigate("/search?q=kito&page=1");

// 获取参数
const [searchParams] = useSearchParams();
const q = searchParams.get("q"); // "kito"
const page = searchParams.get("page"); // "1"

Vue Router 示例

// 跳转(传递参数)
router.push({ path: "/search", query: { q: "kito", page: 1 } });

// 获取参数
const q = useRoute().query.q; // "kito"
const page = useRoute().query.page; // "1"

原理

查询参数的底层是 URL 的 search 部分

  1. 浏览器解析 ?key=value,存储在 window.location.search
  2. 在 SPA 中,路由库会解析 window.location.search 并转换为对象,供前端使用

特点

  • 参数在 URL 中可见,适合筛选、搜索等操作
  • 只能传递字符串,复杂对象需序列化

隐式传参(State / 内存传参)

适用场景

  • 传递临时数据(如表单提交后的提示消息)
  • 传递复杂对象(如 JSON 数据)
  • 不希望参数暴露在 URL 中

React Router 示例

// 跳转(传递参数)
navigate("/home", {
  state: { from: "login", message: "Hello Kito!" }
});

// 获取参数
const { state } = useLocation();
console.log(state.from); // "login"
console.log(state.message); // "Hello Kito!"

Vue Router 示例

Vue Router 没有直接提供 state,但可以用 paramsmeta 实现类似效果

// 方式一:使用 params(不显示在 URL)
router.push({
  path: "/home",
  params: { from: "login" } // 类似 React 的 state
});
const from = useRoute().params.from; // "login"

// 方式二:使用 meta(需提前在路由配置里定义)
router.push({
  path: "/home",
  meta: { requiresAuth: true } // 通常用于权限控制
});
const requiresAuth = useRoute().meta.requiresAuth; // true

原理

隐式传参的底层是 history.pushState API

  1. 当调用 navigate("/home", { state })router.push({ params }) 时,路由库会调用:

    history.pushState(state, "", pathname);
    • state 会被存储在浏览器的会话历史记录(session history)
    • 它不会出现在 URL 里,也不会触发页面刷新
  2. 当用户导航到该页面时,路由库会从 history.state 中读取数据:

    const state = history.state; // { from: "login" }
  3. 刷新页面后 state 会丢失,因为浏览器会重新加载页面,而 history.state 仅存在于当前会话

特点

  • 可传递任意数据(对象、数组等)
  • 不会污染 URL,适合敏感数据
  • ​刷新页面后数据会丢失​​(除非使用 SPA 或持久化存储)

总结

隐式传参在某些场景下更加灵活,合理选择传参方式,可以让代码更清晰、用户体验更好!