在 Vue 项目中使用 URL Query 保存和恢复搜索条件
在实际的前端开发中,我们经常会遇到这样的需求:
用户在列表页输入了一些搜索条件,点击某一条数据进入详情页;当他返回列表页时,希望搜索条件能被 记住,而不是重新初始化。
常见的解决方案有三种:
- 使用 全局状态管理(Vuex/Pinia) 保存搜索条件。
- 使用
keep-alive
缓存页面组件。 - 使用 URL Query 参数 把搜索条件保存在地址栏中。
本文介绍的是第三种方式,通过封装一个 useQueryStorage
Hook,把对象序列化到 URL 的 querystring 中,从而实现搜索条件的记忆。
核心代码
ini
import { isEqual } from "lodash-es";
import { useRouter, useRoute } from "vue-router";
export const useQueryStorage = <T>(key: string = "savedQuery") => {
const router = useRouter();
const route = useRoute();
// 把对象以 JSON 的格式存入到 URL 的 querystring 中
const saveObjectToQueryString = (obj: T) => {
const query = parseSavedObjectFromQueryString();
if (!isEqual(query, obj)) {
router.replace({
query: {
...route.query,
[key]: encodeURIComponent(JSON.stringify(obj)),
},
});
}
};
// 从 URL 的 querystring 中解析出对象
const parseSavedObjectFromQueryString: () => T | null = () => {
let query = route.query[key];
if (query && typeof query === "string") {
query = JSON.parse(decodeURIComponent(query));
return query as T;
}
return null;
};
return {
getQ: parseSavedObjectFromQueryString,
setQ: saveObjectToQueryString,
};
};
代码解析
1. 存储对象到 URL
ini
const saveObjectToQueryString = (obj: T) => {
const query = parseSavedObjectFromQueryString();
if (!isEqual(query, obj)) {
router.replace({
query: {
...route.query,
[key]: encodeURIComponent(JSON.stringify(obj)),
},
});
}
};
这里使用了 JSON.stringify
把对象转成字符串,再用 encodeURIComponent
确保字符串在 URL 中不会出错。
为什么要用 lodash.isEqual
?
👉 因为 Vue Router 的 replace
会更新 URL,如果我们每次都写入同样的对象,就会产生冗余的路由更新。用 isEqual
做深度比较,可以避免不必要的刷新。
2. 从 URL 解析对象
ini
const parseSavedObjectFromQueryString: () => T | null = () => {
let query = route.query[key];
if (query && typeof query === "string") {
query = JSON.parse(decodeURIComponent(query));
return query as T;
}
return null;
};
这一段逻辑就是把 querystring
里的值取出来,做 解码 + JSON 反序列化,还原成原来的对象。
3. Hook 的返回值
kotlin
return {
getQ: parseSavedObjectFromQueryString,
setQ: saveObjectToQueryString,
};
对外提供两个方法:
getQ()
:获取保存的搜索条件。setQ(obj)
:设置搜索条件并保存到 URL。
这样调用方的代码就会非常简洁。
使用示例
在列表页中:
ini
const { getQ, setQ } = useQueryStorage<{ keyword: string; page: number }>();
// 初始化时恢复
const saved = getQ();
if (saved) {
searchForm.keyword = saved.keyword;
searchForm.page = saved.page;
}
// 用户点击搜索时保存
function handleSearch() {
setQ({ keyword: searchForm.keyword, page: searchForm.page });
}
当用户进入详情页再返回时,URL 中依然保存了搜索条件,页面加载时会自动恢复。
优点总结
- 刷新不丢失
因为状态存放在 URL 里,刷新后依然可以恢复。 - 可分享链接
用户可以直接复制 URL,别人打开时能看到相同的搜索条件。 - 解耦全局状态
不依赖 Vuex/Pinia,逻辑简单清晰。
缺点是:如果搜索条件非常复杂,URL 会变长,可能不太美观。
总结
useQueryStorage
是一个非常实用的小 Hook,通过 encodeURIComponent
和 JSON.stringify
将对象持久化到 URL 的 query 参数中,结合 lodash.isEqual
避免重复写入,能很好地解决 列表页返回时记住搜索条件 的问题。