在日常前端开发中,我们经常会遇到这样的需求:
用户在
input框中输入内容后,执行某个函数
例如:搜索联想、表单校验、接口请求等。
看似简单,但实际开发中存在几个非常容易踩坑的问题:
input事件触发过于频繁,影响性能- 需要防抖 / 节流来控制执行频率
- 中文输入法(IME)输入过程中不应该触发逻辑
本文将一步步解决这些问题,并给出一套完整、可靠的解决方案。
一、增加防抖,当用户输入停止再执行操作
<input id="input" type="text" />
<script>
const input = document.getElementById('input')
input.addEventListener('input', (e) => {
doSomething(e.target.value)
})
function doSomething(value) {
console.log('执行逻辑:', value)
}
</script>
这就是最基础的,每次输入都会执行方法,下面再看加上防抖之后的:
<input id="input" type="text" />
<script>
const input = document.getElementById('input')
function debounce(fn, delay = 300) {
let timer = null
return function (...args) {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
function doSomething() {
console.log('执行逻辑:', input.value)
}
input.addEventListener('input', debounce(doSomething, 300))
</script>
加上防抖后,只有当输入停止设定的时间后,才会触发方法,大大减少了执行的频率,但是还有一个问题,就是输入中文的时候,它也会在停止一段时间后执行doSomething方法,会打印出类似 执行逻辑: zhang’san 这种中文的拼音,这个是没有什么意义的。
二、增加中文的监听
浏览器也提供了中文的处理方法(composition),代码如下:
<input id="input" type="text" />
<script>
const input = document.getElementById('input')
function debounce(fn, delay = 300) {
let timer = null
return function (...args) {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
let isComposing = false
const doSomethingDebounced = debounce((value) => {
doSomething(value)
}, 300)
input.addEventListener('compositionstart', () => {
isComposing = true
})
input.addEventListener('compositionend', (e) => {
isComposing = false
// 中文输入完成后,手动触发一次
doSomethingDebounced(e.target.value)
})
input.addEventListener('input', (e) => {
// 中文输入过程中不执行
if (isComposing) return
doSomethingDebounced(e.target.value)
})
function doSomething(value) {
console.log('最终执行:', value)
}
</script>
这样做了后,就可以看到,用户输入拼音时,无论等待多久,都不会执行方法,只有在选完中文后,才会执行。
下面再给一个vue的版本的:
<template>
<el-input
v-model="searchValue"
style="width: 100%"
placeholder="请输入"
@input="handleInput"
@compositionstart="handleCompositionStart"
@compositionend="handleCompositionEnd"
>
</el-input>
</template>
<script setup>
import { ref } from "vue";
cosnt searchValue = ref("");
// 中文输入状态标志
const isComposing = ref(false);
// 防抖定时器
let debounceTimer = null;
// 处理中文输入开始
const handleCompositionStart = () => {
isComposing.value = true;
};
// 处理中文输入结束
const handleCompositionEnd = () => {
isComposing.value = false;
// 中文输入结束后触发搜索
performSearch();
};
// 处理输入事件(防抖)
const handleInput = () => {
// 如果正在输入中文,不触发搜索
if (isComposing.value) {
return;
}
// 清除之前的定时器
if (debounceTimer) {
clearTimeout(debounceTimer);
}
// 设置新的防抖定时器(300ms)
debounceTimer = setTimeout(() => {
performSearch();
}, 300);
};
// 执行搜索
const performSearch = () => {
console.log("当前输入框内容:",searchValue.value)
};
</script>

2919

被折叠的 条评论
为什么被折叠?



