安全保存搜索历史需初始化数组、读写校验类型、去重保序(小写比对+原词存储)、限制长度、onUnload统一保存,并用getStorageInfoSync排查异常。

uni-app 里用 uni.setStorageSync 保存搜索词到本地没问题,但直接存字符串数组容易出错
很多人一上来就写 uni.setStorageSync('searchHistory', ['苹果', '香蕉']),看似正常,但后续读取时如果没做容错,uni.getStorageSync 返回 null 或非数组类型就会报错(比如 Cannot read property 'map' of null)。真正安全的做法是:始终把历史记录当作数组初始化,并在读写前后做类型校验。
- 写入前先读一次,确保拿到的是数组;不是就重置为空数组
- 去重逻辑要放在写入前,避免重复 push 相同关键词
- 限制长度(比如最多 10 条),老的自动移除,用
.splice(0, 1)比.shift()更可控
搜索词去重和排序不能只靠 Array.from(new Set())
new Set() 确实能去重,但它会打乱原有顺序——而搜索历史需要“最新搜索排最前”。所以得手动维护插入位置:新词放开头,再过滤重复项,最后截断。另外注意大小写敏感问题,用户搜 iPhone 和 iphone 通常应视为同一词。
- 统一转小写比对,但保留原始输入存入数组(显示时用原词)
- 用
history.findIndex(item => item.toLowerCase() === keyword.toLowerCase())判断是否已存在 - 已存在就先
.splice(index, 1)删除,再.unshift(keyword)插到开头
页面卸载前保存比每次输入都存更合理
在搜索框 @input 里频繁调用 uni.setStorageSync 不仅没必要,还可能因小程序后台限制或异步时机导致丢失。正确时机是:用户点击搜索(触发跳转或请求)后、或者离开搜索页前(onUnload)再统一保存。
- 在
onUnload生命周期里保存,覆盖所有退出路径(包括左滑返回、tab 切走) - 不要在
@confirm同时做搜索请求 + 保存,网络慢时保存可能滞后,建议请求成功后再存 - 如果用了防抖(debounce),更要避免 debounced 函数里调用同步存储——它可能被取消,导致漏存
真机调试时 uni.getStorageInfoSync 能帮你快速定位清空异常
有时发现历史记录突然没了,不一定是代码逻辑错,可能是开发者工具缓存假象,或真机上被微信/支付宝主动清理。用 uni.getStorageInfoSync 查看当前 storage 总大小和键列表,能立刻确认是不是被清空、或是键名拼错了(比如存成了 search_history 却读 searchHistory)。
- 加个临时按钮执行:
console.log(uni.getStorageInfoSync()) - 注意
uni.removeStorageSync没有回调,失败也不报错,务必配合getStorageInfoSync验证 - 安卓某些定制系统会限制单个 key 大小(超 2MB 可能静默失败),历史词不宜存过长字符串(如带时间戳、URL 参数的完整 query)


















