前言
在开发 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 路径匹配:
- 浏览器发送请求时,服务器或前端路由(如
vue-router
)解析 URL,提取:id
部分 - 在 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
部分:
- 浏览器解析
?key=value
,存储在window.location.search
- 在 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
,但可以用 params
或 meta
实现类似效果
// 方式一:使用 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:
当调用
navigate("/home", { state })
或router.push({ params })
时,路由库会调用:history.pushState(state, "", pathname);
state
会被存储在浏览器的会话历史记录(session history)中- 它不会出现在 URL 里,也不会触发页面刷新
当用户导航到该页面时,路由库会从
history.state
中读取数据:const state = history.state; // { from: "login" }
- 刷新页面后
state
会丢失,因为浏览器会重新加载页面,而history.state
仅存在于当前会话
特点
- 可传递任意数据(对象、数组等)
- 不会污染 URL,适合敏感数据
- 刷新页面后数据会丢失(除非使用 SPA 或持久化存储)
总结
隐式传参在某些场景下更加灵活,合理选择传参方式,可以让代码更清晰、用户体验更好!