如何调整focusout与click事件触发顺序?解决输入框补全点击冲突
解决focusout与自动补全click事件的触发顺序冲突
这个问题其实是浏览器事件触发机制导致的典型场景——当你点击自动补全弹窗里的选项时,输入框的focusout事件会先于click事件触发。这就导致你的focusout逻辑先清空了结果列表或者修改了输入值,等到click事件执行时,目标元素可能已经不存在,自然无法正常触发选择逻辑。
下面给你几个实用的解决方案,结合你的代码来修改:
方案1:通过延迟执行focusout逻辑,给click事件留足时间
利用setTimeout给focusout里的操作加一个短暂延迟(比如100ms),让click事件先完成执行,再处理focusout的收尾逻辑:
inputFrom.addEventListener('focusout', () => { setTimeout(() => { const list = document.querySelector('#results-from'); let first = list.firstChild; inputFrom.value = first.getAttribute('data-display'); resultsFrom.innerHTML = ''; }, 100); // 100ms的延迟足够让click事件先触发 });
这个方案优点是改动最小,兼容性好,几乎不需要调整原有逻辑。
方案2:通过relatedTarget判断是否点击弹窗内元素
focusout事件对象的relatedTarget属性会指向即将获得焦点的元素,我们可以检查这个元素是否在自动补全弹窗内部。如果是,说明用户点击的是建议项,此时跳过focusout里的清空/赋值逻辑:
inputFrom.addEventListener('focusout', (event) => { const resultsFrom = document.querySelector('#results-from'); // 检查即将获得焦点的元素是否属于弹窗 if (resultsFrom.contains(event.relatedTarget)) { return; // 直接返回,不执行后续逻辑 } // 原有的focusout逻辑 const list = document.querySelector('#results-from'); let first = list.firstChild; inputFrom.value = first.getAttribute('data-display'); resultsFrom.innerHTML = ''; });
这个方案更优雅,没有延迟,用户体验更好,是优先推荐的解决方式。
方案3:改用mousedown事件处理选项点击
mousedown事件的触发时机早于focusout,所以我们可以把原有的click事件换成mousedown,让选项选择逻辑先执行,再触发focusout的清空操作:
// 把click换成mousedown resultsFrom.addEventListener('mousedown', (event) => { let e = event.target.parentNode; inputFrom.value = e.getAttribute('data-display'); });
这个方案的好处是不需要修改focusout的逻辑,直接调整事件类型即可,但要注意:如果用户用键盘选择建议项(比如回车),还是需要单独处理键盘事件。
你可以根据自己的场景选择最合适的方案,一般来说方案2的体验最佳~
内容的提问来源于stack exchange,提问作者Bonapara
相关产品推荐
相关产品推荐

