在使用 ElSelect 组件的 onInput 事件时,由于每次输入都触发搜索,导致请求频繁且新搜索结果覆盖了旧结果,无法实现输入数据的累积搜索。我们希望的是,每次搜索能够将新的输入内容与之前的内容拼接显示,从而实现用户的诉求。
ElSelect 组件
<ElSelectref={storeRef}filterableremoteremoteMethod={getSiteList}multipleclearablev-model={queryForm.value.pickUpSiteIdList}placeholder="请输入门店名称"onInput={(e) => { handleInput(e?.data || '', SelectEnum.store); }}>{siteList.value?.map((item) => (<ElOption label={item.siteName} value={item.siteId} />))}
</ElSelect>
onInput 事件
const handleInput = (query, type) => {if (type === SelectEnum.store) {storeRef.value.remoteMethod(query);}
};// 其余
const getSiteList = async (query = '') => {if (query) {const res = await querySiteList({siteName: query,});siteList.value = res.records;} else {siteList.value = [];}
};
目前现状展示,后面搜索的结果覆盖之前的搜索结果o(╥﹏╥)o。
可能第一反应就是,使用函数防抖,OK。
import { debounce } from 'lodash';const handleInput = debounce((query, type) => {if (type === SelectEnum.store) {storeRef.value.remoteMethod(query);}
}, 500);
展示为:
虽然效果好一些,但仍不是我们想要的结果,我希望搜索的是「上海南」,而不是「上海」「南」 。
可能会觉得,时间拉长点,会不会好一点,展示一下:
const handleInput = debounce((query, type) => {if (type === SelectEnum.store) {storeRef.value.remoteMethod(query);}
}, 2000);
显而易见,更加糟糕,因为间隔时间变长,对应的搜索也就更加精确,最后一次搜索就是「站」。
不妨换一个思路:
将之前的输入与当前输入拼接起来,每次用户输入时,等一小段时间再发起请求,这样可以减少请求次数并避免连续输入时产生多个请求。
const searchContent = ref(''); // 当前输入框内容,拼接所有输入的内容
// 防抖定时器
let timeoutId = null;const handleInput = (query, type) => {// 处理输入拼接searchContent.value += query;// 清除之前的定时器,防止连续输入时发送多个请求if (timeoutId) {clearTimeout(timeoutId);}// 使用防抖,延迟搜索timeoutId = setTimeout(() => {if (type === SelectEnum.store) {storeRef.value.remoteMethod(searchContent.value);}}, 500); // 500ms 的防抖延迟
};
运行发现一个比较诧异的现象,输入内容包括那么多拼音,也不是我们想要的。
再改进一下:
需要解决 累积拼接输入时产生的错误!!!这种问题通常是因为 onInput 事件触发时处理不当,导致历史内容和当前输入被错误拼接。
解决方法:以输入框当前值为准!
// 防抖定时器
let timeoutId = null;const handleInput = (query, type) => {// 清除之前的定时器,防止连续输入时发送多个请求if (timeoutId) {clearTimeout(timeoutId);}// 防抖延迟timeoutId = setTimeout(() => {nextTick(() => {if (type === SelectEnum.store) {const inputValue = storeRef.value?.$el.querySelector('input')?.value || '';storeRef.value.remoteMethod(inputValue);}});}, 500); // 防抖延迟 500ms
};
代码解释:
每次 onInput 事件触发时,直接使用 storeRef 引用直接获取输入框中当前的完整值,确保内容是正确的,而不是依赖传入的 onInput 参数或直接拼接,这避免了累积拼接错误。
使用 nextTick,确保在 DOM 更新后获取到最新的输入框值。
OK,到处实现完美解决!