本文针对JavaScript开发中常见的下拉框blur与click事件冲突问题,深入分析了事件触发顺序及单线程执行机制。通过两个实际案例,分别提供了使用setTimeout延迟blur执行和将click替换为mousedown两种解决方案,确保下拉选项能正确选中并赋值。
解决blur与click冲突
解决blur与click冲突
前言:
在前端开发过程中,blur和click事件的冲突是一个高频出现的难题。本文将通过一个典型的“下拉框”应用场景,详细阐述该问题,并提供两种行之有效的解决思路。
blur和click事件简述
一、blur和click事件简述
- blur事件:当元素失去焦点时触发。它属于表单事件,值得注意的是,blur和focus事件不会发生冒泡,而其他大多数表单事件是可以冒泡的。
- click事件:当用户点击元素时触发。该事件适用于所有元素,并且会产生冒泡现象。
示例1:blur事件为表单事件
<input type="text" id="tel">
<script>
document.addEventListener("blur", function(){
console.log("my document blur");
});
var ipt = document.getElementById("tel");
ipt.addEventListener("blur", function(){
console.log("my input blur");
});
</script>
// 输出结果:document为非表单元素
my input blur
示例2:click事件可冒泡
<input type="text" id="tel">
<script>
document.addEventListener("click", function(){
console.log("my document click");
});
var ipt = document.getElementById("tel");
ipt.addEventListener("click", function(){
console.log("my input click");
});
</script>
// 输出结果:
my input click
my document click
示例3:点击某元素导致前一个元素失去焦点,blur事件优先于click事件
<input type="text" id="ipt">
<input type="button" id="btn" value="点我">
<script>
var ipt = document.getElementById("ipt");
ipt.addEventListener("blur", function(){
console.log("my input blur");
});
var btn = document.getElementById("btn");
btn.addEventListener("click", function(){
console.log("my button click");
});
</script>
// 输出结果:
my input blur
my button click
下拉框blur和click事件冲突,导致不能正常选择值
二、下拉框blur和click事件冲突,导致不能正常选择值
在实际业务场景中,我们常需实现这样的交互:点击输入框时显示下拉列表,点击列表外区域时隐藏列表,而点击列表内的子元素则选中该项。这种需求往往会导致事件冲突。
<!-- DOM结构示意 -->
<input type="text" placeholder="请选择姓氏" readonly>
<div class="search-list" data-status="hide">
<ul>
<li><a href="javascript:">赵</a></li>
<li><a href="javascript:">钱</a></li>
<li><a href="javascript:">孙</a></li>
<li><a href="javascript:">李</a></li>
</ul>
</div>
/** 说明:
* 目前通过ul外层div自定义属性“data-status”控制其是否显示
*/
(function($){
$("input").focus(function(){
// input框获取焦点,展示下拉框
$(".search-list").attr("data-status", "show");
}).blur(function(){
// input框失去焦点,隐藏下拉框
$(".search-list").attr("data-status", "hide");
});
// 选择对应选项,并赋值给input框
$(".search-list li a").click(function(){
console.log("执行");
$("input").val($(this).text());
});
})(jQuery);
若直接执行上述代码,会发现无法正确获取下拉框中的值。
原因分析:JavaScript是单线程模型,同一时刻只能处理一个事件。结合示例3可知,“blur优先于click执行”。在本例中,blur处理程序会立即隐藏下拉展示区,导致后续的click事件无法在目标元素上正常触发,因此console日志也不会输出。
解决方案1:对blur事件进行延迟,让click先执行。
(function($){
$("input").focus(function(){
// input框获取焦点,展示下拉框
$(".search-list").attr("data-status", "show");
}).blur(function(){
setTimeout(function(){
// input框失去焦点,隐藏下拉框
$(".search-list").attr("data-status", "hide");
}, 300);
});
// 选择对应选项,并赋值给input框
$(".search-list li a").click(function(){
console.log("执行");
$("input").val($(this).text());
});
})(jQuery);
使用mousedown让其优先执行
三、使用mousedown让其优先执行
示例4:将示例3中的click事件改为mousedown
<input type="text" id="ipt">
<input type="button" id="btn" value="点我">
<script>
var ipt = document.getElementById("ipt");
ipt.addEventListener("blur", function(){
console.log("my input blur");
});
var btn = document.getElementById("btn");
btn.addEventListener("mousedown", function(){
console.log("my button mousedown");
});
</script>
// 输出结果:
my button mousedown
my input blur
mousedown事件:当鼠标指针移动到元素上方并按下鼠标按键时触发。
mouseup事件:当在元素上松开鼠标按钮时触发。
注意:
(1)mousedown 与 click 事件不同,mousedown 事件仅需要按键被按下,而不需要松开即可发生。 (2)mouseup 与 click 事件不同,mouseup 事件仅需要放松按钮。当鼠标指针位于元素上方时,放松鼠标按钮就会触发该事件。
补充:mousedown、mouseup、click
<input type="button" id="btn" value="点我">
var btn = document.getElementById("btn");
btn.addEventListener("mousedown", function(){
console.log("my button mousedown");
});
btn.addEventListener("click", function(){
console.log("my button click");
});
btn.addEventListener("mouseup", function(){
console.log("my button mouseup");
});
输出结果:
my button mousedown
my button mouseup
my button click
因此,其执行顺序为:
mousedown >> mouseup >> click
解决方案2:将click事件改为mousedown,让其优先于blur事件执行
(function($){
$("input").focus(function(){
// input框获取焦点,展示下拉框
$(".search-list").attr("data-status", "show");
}).blur(function(){
// input框失去焦点,隐藏下拉框
$(".search-list").attr("data-status", "hide");
});
// 选择对应选项,并赋值给input框
$(".search-list li a").mousedown(function(){
$("input").val($(this).text());
});
})(jQuery);
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!