@input事件必须绑定,因v-model+watch会漏掉中文拼音中途状态且watch默认立即执行空查询;本地过滤需防抖避免卡顿;输入框值更新需nextTick+值变更检测;远程联想与本地过滤须物理隔离并加竞态控制。

@input 事件必须绑定,不能用 v-model + watch 替代
uni-app 的 @input 是唯一能捕获每次输入(含删除、中文拼音中途状态)的事件,v-model 虽方便,但若配合 watch 监听搜索值,会漏掉中间态——比如用户在 iOS 上打「shang」还没选词,watch 根本不触发,联想就卡住。更糟的是,watch 默认会立即执行一次空查询(除非显式设 immediate: false),白跑一请求。
实操建议:
- 模板里写
,不用v-model(避免和过滤逻辑耦合) -
onInput方法里直接取e.detail.value,别依赖this.searchValue的响应式更新节奏 - 如果非要用
v-model,确保data中初始化searchValue: '',且watch显式声明{ immediate: false }
本地过滤必须防抖,否则长列表会卡顿闪动
没加防抖的 @input 在用户连敲「北京朝阳区」时,会触发 7 次同步 filter(),尤其当原始数组有几百项、每项都做 includes() 或正则匹配时,UI 线程直接被占满,输入延迟肉眼可见。
实操建议:
- 定义
data中的filterTimer: null -
onInput里先clearTimeout(this.filterTimer),再this.filterTimer = setTimeout(() => { this.doLocalFilter(val) }, 300) -
doLocalFilter内部用toLowerCase()统一比对,避免大小写导致漏匹配:list.filter(item => item.name.toLowerCase().includes(val.toLowerCase())) - 空字符串时直接返回原数组,不走
filter(),减少无谓计算
过滤赋值后 input 内容不更新?关键在 nextTick + 值变更检测
常见现象:限制只能输字母,用户连按「123abc」,输入框只显示「abc」,但「123」那段始终卡在框里不动——这是因为 uni-app 的视图更新机制会跳过“相同值”的赋值,哪怕你已经用正则清掉了非法字符。
实操建议:
- 不要直接
this.searchValue = filteredVal,尤其当filteredVal可能为空字符串时 - 必须用
this.$nextTick(() => { this.searchValue = filteredVal })确保 DOM 同步 - 确保
filteredVal和上次值不同,比如连续输空格,先赋一个临时值再赋真实值:this.searchValue = '_'; this.$nextTick(() => { this.searchValue = filteredVal }) - 安卓真机上若仍失效,加一行
uni.hideKeyboard()强制收起键盘再赋值
远程联想和本地过滤必须物理隔离
把接口联想词和本地数组过滤塞进同一个 computed 或共用一个 filteredData 数组,必然出问题:用户搜「sh」,本地立刻筛出「上海」「深圳」,同时接口返回「石家庄」「沈阳」,两个结果互相覆盖,UI 频繁重绘,甚至出现「搜 sh 却显示北京」这种错乱。
实操建议:
- 拆成两个独立字段:
localFiltered(computed 或方法实时算)、remoteSuggestions(仅由fetchSuggestions赋值) - 渲染时手动合并:
[...this.localFiltered, ...this.remoteSuggestions],再用Set去重 - 远程请求加竞态控制:每次发新请求前,先
if (this.lastReqId) cancel(this.lastReqId),或用时间戳比对丢弃旧响应 - 用户清空输入框时,清
remoteSuggestions,但保留localFiltered为全量(除非明确要重置)
真正麻烦的不是写过滤逻辑,而是处理 iOS 中文输入法的拼音未确认态、安卓软键盘失焦不收起、以及同一输入框既要本地秒滤又要等接口返回还不打架——这些点不提前卡死,上线后就是线上事故。











