必须手动防抖,否则请求会失控;需用 settimeout + cleartimeout 手写防抖,延迟设为300ms,声明 searchtimer 存定时器id,输入为空或长度变化时更新,用 filter 而非 indexof 判断重复,限制历史最大条数为10并用 history.pop() 删除尾部,模糊匹配需预建索引,页面卸载时清理定时器、关键词 trim、联想面板用 v-show。

@input 必须手动防抖,否则请求会失控
uni-app 的 @input 事件在每个字符变化时都触发,不是“用户停顿后才发”,输 “北京” 会依次触发 “北”、“北京” 两次——不加控制,后端可能被刷崩,前端列表还会跳变、覆盖错乱。
- 用
setTimeout+clearTimeout手写最稳,别信文档里说的“uni-app 内置防抖”(它根本没有) - 延迟设为
300,太短压不住,太长(如800)用户会觉得卡顿 - 声明一个
searchTimer变量存定时器 ID,每次@input先clearTimeout(this.searchTimer),再重新赋值 - 输入为空或长度
时,直接清空<a style="color:#f60; text-decoration:underline;" title="联想" href="https://m.php.cn/zt/17126.html" target="_blank">联想</a>列表,不发请求——避免搜“的”“了”这种无效词
联想列表必须用 v-if 控制显隐,v-show 会埋坑
用 v-show="showSuggestions" 看似简单,但 DOM 一直存在:iOS 上键盘弹起时列表被顶跑、点击穿透失效、z-index 遮挡按钮,真机上尤其明显。
- 改用
v-if="showSuggestions && suggestionList.length",真正销毁/重建节点 - 请求中、失败、无结果三种状态要分开处理:loading 中显示骨架,失败时清空并留提示,空数组时不渲染
- 定位用
position: absolute+z-index,父容器加position: relative,否则 iOS 下容易错位 - 别忘了加
transition淡入淡出,否则列表“啪”一下闪出来,体验生硬
点击联想词后必须显式赋值 + 调搜索 + 收键盘
常见现象:点了“iPhone 15”,输入框没变、没跳转、键盘还开着——根本原因是只改了 v-model 绑定值,没同步触发业务逻辑。
- 点击项时立即执行:
this.searchValue = item; this.doSearch();,别等@confirm或失焦 - 调
uni.hideKeyboard()强制收起软键盘,App 端(尤其 iOS)不收就卡焦点 - 如果用了
focus控制输入框聚焦状态,记得设this.focus = false,否则光标还在闪,干扰下一步操作 - 安卓真机上
confirm-type="search"有时不触发@confirm,必须靠点击事件兜底
历史记录不能直接 push,要去重 + 限长 + trim
直接 history.push(newWord) 再 uni.setStorageSync('history', history),会导致“苹果”“苹果 ”“苹果手机”全堆在一起,越用越慢,匹配越不准。
- 存之前先
newWord.trim(),避免空格导致重复 - 去重用
history = history.filter(item => item !== newWord),别用indexOf判是否存在——万一有多个相同词,filter 更安全 - 限制最大条数(比如
10),超出后history.pop()删尾部;别用splice(0, -1),这个写法逻辑反了 - 如果要做模糊匹配(输“苹”出“苹果”),得提前建索引数组,别现场
includes查,大数据量下卡顿明显
v-show 而非 v-if——这三个点,上线后最容易被忽略,也最容易在真机上暴露问题。











