You need to enable JavaScript to run this app. 如何实现input失焦隐藏下拉前先触发子元素的点击事件
优惠活动
大模型
产品
解决方案
定价
更多

如何实现input失焦隐藏下拉前先触发子元素的点击事件

问题根因

问题来自两方面原因:

  • CSS的下拉展开逻辑完全绑定在input的聚焦状态上:只要input触发blur失焦,相邻的.child-2容器就会从max-height:500px缩回max-height:0。浏览器原生事件时序中,mousedown先于click触发,点击下拉选项时首先会让input失焦,下拉容器会在click事件完整触发前就隐藏到可视范围外,导致点击根本无法落到grandchild元素上,也就是感知到的“失焦先于点击执行”。
  • 原生JS代码本身存在逻辑bug,即使解决失焦问题,原代码也无法正常运行:
  • 文本匹配时判断对象是整个NodeList的innerHTML,不是单个grandchild的文本内容,所有选项的显示隐藏逻辑都会出错
  • 每次keyup触发时都给grandchild重复绑定click事件,会造成事件监听器叠加
  • 循环内绑定的click回调直接引用循环变量x,存在闭包取值问题,即使绑定成功也会出现内容取值错误
解决方案

核心处理:避免input提前失焦

最稳定的做法是给整个下拉容器绑定mousedown事件,在回调中调用e.preventDefault()。这个操作会阻止浏览器在mousedown阶段自动触发input的失焦流程,等下拉选项的完整click事件执行完毕后,再处理后续的状态切换。
如果需要保留失焦后自动收起下拉的逻辑,可以把失焦的状态判断放在100-200ms的定时器延迟中执行,给点击事件留足触发时间。

配套修复原有代码的逻辑问题

  • 不要在keyup的循环逻辑里重复绑定事件,把grandchild的click监听器提到外部,只做一次绑定
  • 过滤判断时逐个遍历每个grandchild的文本内容做匹配,不要对整个NodeList做判断
  • 用forEach循环或者let声明循环变量,避免闭包取值错误
修正后的可运行核心代码
// 文本包含判断工具
function isContainText(source, target) {
  return source.toLowerCase().includes(target.toLowerCase());
}
const fieldInput = document.querySelector(".child-1");
const dropdown = document.querySelector(".child-2");
const optionItems = document.querySelectorAll(".grandchild");

// 仅绑定一次选项点击事件
optionItems.forEach(item => {
  item.addEventListener("click", function() {
    console.log(this.textContent.trim());
  });
});

// 阻止下拉容器区域的默认失焦行为
dropdown.addEventListener("mousedown", e => {
  e.preventDefault();
});

// 输入过滤逻辑
fieldInput.addEventListener("keyup", function() {
  const keyword = this.value.trim();
  optionItems.forEach(item => {
    const match = isContainText(item.textContent, keyword);
    item.style.display = match ? "block" : "none";
  });
});

内容的提问来源于stack exchange,提问作者Irvan Hilmi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.31 21:06:07