App端搜索历史必须用uni.setStorageSync,读取在onLoad中判空初始化,去重采用filter旧项+unshift新词+slice(0,10)保序截断,避免Array.from(new Set())打乱顺序,禁用@input高频写入以防卡顿丢数据。

uni-app里搜索历史怎么存才不丢、不卡、不乱序
App端必须用uni.setStorageSync,不是“推荐”,是硬性要求。iOS后台挂起约3秒后进程被冻结,uni.setStorage的回调大概率不执行,历史记录就丢了。Android上冷启动时created钩子甚至可能早于存储模块初始化,读出来是undefined。
去重逻辑不能靠Array.from(new Set())——会打乱时间顺序;也不能push完再filter——旧项还在数组里,新词插不到最前。正确做法是:读出原数组 → filter掉同名旧项 → unshift新词 → slice(0, 10)截取。
- 读取必须放在
onLoad或onShow里,data()和created不可靠 - 首次读取要判空:
uni.getStorageSync('searchHistory') || [] - 截取操作一定放最后,否则
unshift进去的新词可能被slice切掉
@input触发联想时为什么总发多余请求?防抖没生效的典型原因
别用@keyup或@blur,统一走@input。但光加lodash.debounce还不够——如果输入长度
防抖函数本身没问题,问题常出在触发条件没兜住:用户删到1个字、又快速补回,中间searchValue短暂为1位,请求就发出去了。
- 在
handleInput里先判断if (this.searchValue.length - 防抖延迟设300ms,800ms以上用户会觉得卡顿,100ms以下压不住连打
- 不用
setTimeout手写防抖,直接import { debounce } from 'lodash'更稳(v3项目可配auto-import)
点击历史记录后输入框没更新、键盘没收、搜索没触发
点历史项不是简单赋值this.searchValue = keyword就完事。iOS软键盘常残留,Android部分机型不响应focus(),而且@confirm只对回车有效,列表项点击得手动串行三件事。
uni-search-bar组件自带@confirm,但历史项点击是独立@click,必须显式调用uni.hideKeyboard()收键盘,否则下次进页面键盘自动弹出,体验断裂。
- 赋值后立刻调
this.doSearch(),不能依赖watch监听,有延迟 -
uni.hideKeyboard()要写在赋值之后,且最好包一层setTimeout(() => { ... }, 50)兼容iOS - 如果用了
uni-input自定义组件,确保它绑定了v-model并触发input事件,否则doSearch拿不到最新值
联想列表为什么点不中、遮不住、动画卡
用v-show而不是v-if控制显示,避免反复销毁重建节点;定位必须用position: absolute + z-index,且父容器不能是overflow: hidden——否则列表被裁掉。
常见错误是把联想列表塞进scroll-view里,结果滚动时列表跟着动,或者层级被盖住。它应该脱离文档流,紧贴输入框下方。
- 列表
top值建议用calc(100% + 8px),比固定px值适配性更好 - 不要给列表加
transition做淡入,uni-app里v-show切换本身无动画,强行加反而卡顿 - 点击联想词后,除了赋值还要调
uni.hideKeyboard(),否则键盘挡着列表,用户看不到反馈
真实场景里最易忽略的是:App端onLoad读历史 + setStorageSync写历史 + @input里双校验(长度+防抖),这三处任一漏掉,历史功能就断层。补全服务可以临时mock,但本地逻辑一旦松动,用户感知最直接。











