ElSelect 组件的 onChange 和 onInput 事件的区别
偶然遇到一个问题,在 ElSelect 组件中设置 filterable 属性后,监测不到复制粘贴的内容,也就意味着不能调用接口,下拉框内容为空。
简要代码如下:
<ElSelect
style="width: 256px"
multiple
v-model={siteIdList}
clearable
filterable
remote
remoteMethod={getSiteList}
placeholder="请输入门店名称"
>
{siteList.value.map((item) => (
<ElOption label={item.siteName} value={item.siteId} />
))}
</ElSelect>
对此进行分析。
1. 直观区别
在 ElSelect 组件中,onInput 和 onChange 都是用于监听用户选择内容的事件,区别在于:
1、onInput 事件
触发时机:onInput 事件在用户每次选择新选项时都会立即触发,即每当输入值发生变化(无论是添加or移除),都会触发这个事件。
适用场景:通常用于实时响应用户输入,如动态更新页面数据、过滤、自动填充等。其触发频率较高,更适合于即时性要求较高的场景。
2、onChange 事件
触发时机:onChange 事件仅在用户选择内容发生最终变化并确认时触发。例如,在用户点击选项列表中的某一项完成选择后,onChange 才会触发。重复选择同一个选项不会触发 onChange。
适用场景:更适合在选择操作完成后再进行的逻辑处理,例如提交表单、更新数据等。因为它只在确认选择后触发,频率较低,适合用于非即时响应的场景。
2. 事件挂载
在 ElSelect 组件中,onInput 和 onChange 事件的挂载有明显的不同,这关系到它们在 Vue 中的实现和具体作用。
1、onInput 事件
挂载位置:onInput 事件实际上是与 v-model 绑定的默认事件。在 Vue 中,v-model 会自动绑定组件的 input 事件来更新数据,因此当 ElSelect 的选择值发生变化时,它会触发 onInput 事件,将新值传递给 v-model 绑定的数据。这点需要额外注意📢下!
🌰:
<el-select v-model="selectedValue" @input="handleInput">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
当 selectedValue 更新时,@input 会自动触发,实时同步数据。
2、onChange 事件
挂载位置:onChange 是 ElSelect 自带的事件监听器,与 v-model 没有直接关系。它可以单独挂载在组件实例上,用于检测最终选择的变化。这点需要额外注意📢下!
🌰:
<el-select v-model="selectedValue" @change="handleChange">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
当用户的选择发生最终变化后,@change 会触发 handleChange 方法,而不会在每次切换选项时触发。
总结
3. 解决方法
针对上述分析,可以在 ElSelect 组件上使用 onInput 事件,监听内容的改变。
<ElSelect
ref={storeRef}
style="width: 256px"
filterable
remote
remoteMethod={getSiteList}
onInput={(e) => { handleInput(e?.data || ''); }}
multiple
clearable
v-model={siteIdList}
placeholder="请输入门店名称"
>
{siteList.value?.map((item) => (
<ElOption label={item.siteName} value={item.siteId} />
))}
</ElSelect>
然后在 handleInput 事件上调用 storeRef 的 remoteMethod 事件进一步处理,由此成功解决。
const handleInput = debounce((query, type) => {
storeRef.value.remoteMethod(query);
}, 300);