uni.setstoragesync只接受字符串,存数组需json.stringify,读取需json.parse并兜底空字符串;去重置顶要先删旧再插头最后截断;读取应在onshow,写入在@confirm或搜索成功后;清空需同步storage、data和强制更新。

直接用 uni.setStorageSync 存数组会静默失败,必须先 JSON.stringify;读取时也得 JSON.parse 并兜底空字符串,否则 map 报错或列表空白。
为什么 uni.setStorageSync('search_history', ['苹果']) 有时不生效
因为 uni.setStorageSync 的 value 参数只接受字符串,传入数组会被转成 "apple,banna" 这类无意义字符串,甚至在某些平台(如 iOS App)直接静默丢弃。你后续 uni.getStorageSync('search_history') 拿到的可能是 undefined 或空字符串,JSON.parse 就会崩。
- 写入前必须:
uni.setStorageSync('search_history', JSON.stringify(newHistory)) - 读取时必须:
const history = JSON.parse(uni.getStorageSync('search_history') || '[]') - 别信“默认是数组”——
|| []在JSON.parse前无效,兜底要放在parse的参数里 - H5 端 localStorage 也走这套逻辑,不用额外分支
怎么安全地去重 + 置顶 + 截断到 10 条
不能靠 Array.from(new Set()),它打乱顺序;也不能只 unshift,否则重复词堆在前面。正确做法是:先找旧位置、删掉、再插头、最后截断。
- 用
history.findIndex(item => item.toLowerCase() === keyword.toLowerCase())找旧词(大小写归一) - 找到就
history.splice(index, 1)删除,再history.unshift(keyword) - 没找到就直接
unshift -
slice(0, 10)必须放在最后一步,否则刚插进去的新词可能被截掉 - 关键词需
keyword.trim()后长度 > 0,空格词跳过存储
什么时候读、什么时候写最稳
别在 data() 或 created 里读——App 端存储模块可能还没初始化;也别在 @input 里狂写——安卓卡顿、小程序后台切走易丢数据。
- 读取时机:
onShow(每次页面显示都同步缓存,覆盖热切换、手动清缓存等场景) - 写入时机:
@confirm(软键盘点搜索键)或用户点击历史项后、搜索请求成功回调里 - 避免在防抖函数里调
uni.setStorageSync,它可能被取消导致漏存 - 真机调试时可用
console.log(uni.getStorageInfoSync())查当前 key 列表和总大小,快速定位“删不掉”是不是 key 拼错了
清空历史后 UI 不刷新?三步缺一不可
只调 uni.removeStorageSync('search_history') 或只设 this.historyList = [] 都不行——前者不联动 data,后者不清理缓存,Vue2 下空数组响应式更新还容易失效。
- 第一步:
uni.setStorageSync('search_history', JSON.stringify([]))(别用removeStorageSync,避免后续parse报错) - 第二步:
this.historyList = [](切断旧引用) - 第三步:
this.$forceUpdate()(仅 Vue2 项目必需,H5/APP 环境下对空数组更新不敏感) - 如果用了
computed包装历史列表,记得在清空后手动赋值,否则 getter 仍返回旧值
最易被忽略的是:读取时没做 JSON.parse 兜底、去重时没大小写归一、清空时只动了 data 没动 storage——这三点不出错则已,一出就是“历史时灵时不灵”,查起来极费时间。











