从覆盖到拼接:优化 onInput 事件的输入
在使用 ElSelect 组件的 onInput 事件时,由于每次输入都触发搜索,导致请求频繁且新搜索结果覆盖了旧结果,无法实现输入数据的累积搜索。我们希望的是,每次搜索能够将新的输入内容与之前的内容拼接显示,从而实现用户的诉求。
ElSelect 组件
<ElSelect
ref={storeRef}
filterable
remote
remoteMethod={getSiteList}
multiple
clearable
v-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,到处实现完美解决!