uni-search-bar的@input事件每次字符变化即触发,需手动防抖;联想面板须用v-if控制显隐并清理定时器;历史记录要去重限长;app端需处理键盘收起错位及异步存储。

uni-search-bar 的 @input 事件不是“实时触发”而是“每次输入都触发”
很多人以为 @input 是等用户停顿后才发请求,其实它在每个字符变化时就立刻触发——输“苹果”,会依次触发 “苹”、“苹果”、“苹果手” 三次,不加控制就会打爆后端或卡 UI。
必须自己加防抖,不能依赖组件内置逻辑。官方没提供防抖参数,uni-search-bar 本身也不做节流。
- 用
setTimeout+clearTimeout手写最稳妥,300–500ms 是常见阈值 - 别把防抖逻辑写在
@confirm里——那是用户点搜索或回车才走的路径,和联想无关 - 记得在页面
onUnload或beforeDestroy(Vue2)/onBeforeUnmount(Vue3)里clearTimeout,否则内存泄漏
联想列表渲染必须用 v-if 而非 v-show 控制显隐
用户没输入、没匹配、或请求失败时,联想面板如果只是 v-show="false",DOM 依然存在,可能遮挡下方按钮、影响触摸穿透、甚至在 iOS 上引发滚动错位。
v-if 才能真正销毁/重建节点,配合 transition 做淡入淡出也更干净。
- 推荐结构:
<suggestion-panel v-if="showSuggestions && suggestionList.length"></suggestion-panel> - 别只靠
suggestionList.length判断显隐——空数组但请求中,应显示 loading;请求失败应留空或提示“暂无建议” - 点击联想项后,除了填入输入框,一定要手动调用
searchBarRef.blur()收起键盘,否则在 App 端(尤其 iOS)容易卡住焦点
历史记录不能只存 localStorage,得加去重+长度限制
用户搜过“奶茶”、“奶茶店”、“奶茶加盟”,全塞进数组再渲染,不仅占空间,还会让历史区越来越长、匹配越来越不准。
历史记录本质是辅助记忆,不是日志归档。
- 每次新增前先用
Array.prototype.findIndex查重,已有就splice到开头(置顶) - 限制最多存 10 条,超出就
shift()掉最老的一条 - 别直接
JSON.stringify存整个对象——只存keyword字符串即可,体积小、解析快、不易因字段变更导致解析失败 - App 端注意:uni.getStorage 是异步的,别在
data()里同步读取,应在onLoad或onShow中await uni.getStorage后再赋值
App 端真机调试时,iOS 键盘收起延迟会导致联想面板“闪一下”
这不是代码 bug,是 iOS Webview 的渲染机制:键盘收起动画结束前,页面高度还没恢复,position: absolute 的联想面板会短暂错位或被裁剪。
绕不过去,只能缓解。
- 给联想面板加
transform: translateZ(0)强制硬件加速,减少闪烁感 - 监听
@blur后延迟 100ms 再showSuggestions = false,比立刻隐藏更稳 - 避免在联想面板里放
input或textarea——App 端双输入框 + 键盘切换极易失控











