URLSearchParams构造函数不接受普通对象,只支持字符串、URLSearchParams实例或可迭代对象;多级嵌套需手动扁平化,清空时应保留非过滤参数并避免popstate误触发。
很多人尝试 new URLSearchParams({category: 'shoes', price: '100-500'}),结果得到空实例——这是最常踩的坑。URLSearchParams 构造函数**不接受普通对象**,只接受:string、URLSearchParams 实例、或支持 forEach 的可迭代对象(如 FormData)。
正确做法是先拼好查询字符串,或用 Object.entries() 转成键值对数组再传入:
const filters = { category: 'shoes', brand: 'nike', in_stock: 'true' };const params = new URLSearchParams(Object.entries(filters));// → "category=shoes&brand=nike&in_stock=true"
真实商品筛选常含复合结构:价格区间 { min: 100, max: 500 }、多选标签 ['red', 'large']。这些不能直接塞进 URLSearchParams,否则会转成 tags=red,large 或 price=[object Object],后端无法解析。
price_min=100&price_max=500
tags=red&tags=large(后端按同名多值接收)清空不是简单地 window.location.search = '',那会丢掉分页 page=2、排序 sort=price_asc 等非过滤类参数。应只剔除明确属于“过滤”的键名:
const keepKeys = new Set(['page', 'sort', 'limit']);const url = new URL(window.location.href);const params = new URLSearchParams(url.search);for (const key of params.keys()) { if (!keepKeys.has(key)) params.delete(key);}url.search = params.toString();window.history.replaceState(null, '', url);
注意:replaceState 比 assign 更安全,不触发页面刷新;delete 操作要放在循环外收集 key 再批量删,否则 keys() 迭代器可能跳过项。
如果页面监听了 popstate 来响应参数变化(比如自动重载商品列表),那么用 replaceState 清空参数后,用户点浏览器后退,会回到带旧参数的 URL——这容易造成逻辑错乱。
popstate 回调里加守卫:只处理参数有实质变更的情况(对比 prevSearch 和当前 location.search)pushState 新记录——那会让前进/后退栈膨胀复杂点在于「哪些算过滤参数」需要业务层明确定义并维护一份白名单,漏掉一个就可能导致清空不干净或误删关键参数。