input输入框监听输入的正确姿势

在日常前端开发中,我们经常会遇到这样的需求:

用户在 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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值