使用Vanilla JS实现点击元素或触发按钮外部时关闭对应组件
问题原因
你的代码存在3个核心错误:
- 逻辑运算符使用错误:
e.target !== (dateForm || fulfillSetButton)中的||是短路或运算符,只要前面的dateForm是存在的真值,整个表达式永远返回dateForm,相当于你只判断了点击目标不是表单本身,完全没有校验触发按钮的情况。 - 判断逻辑本身错误:你原本描述的触发关闭的条件
(触发按钮未被点击)OR(表单未被点击)逻辑上是错的,因为你不可能同时点击两个元素,这个条件永远为真,不管点哪里都会触发关闭。正确的关闭条件应该是点击目标既不在触发按钮上,也不在表单范围内。 - 没有考虑子元素点击场景:就算你修正了运算符,只判断
e.target是否等于两个元素本身也不行——用户点击表单内的输入框、加减按钮等子元素时,e.target并不是dateForm本身,会被错误判定为点击了外部区域,触发表单关闭。
另外点击触发按钮的事件会冒泡到根节点的点击监听器,你刚给表单加的active类会立刻被监听器删掉,看起来就像点击按钮没反应一样。
修复方案
直接修改全局的关闭逻辑,用Element.contains()方法判断点击目标是否在指定元素范围内,不需要额外加事件阻止冒泡:
// 替换你原来写的失效的外部点击关闭代码 html.addEventListener("click", function(e){ const clickOnButton = fulfillSetButton.contains(e.target); const clickOnForm = dateForm.contains(e.target); // 只有点击既不在按钮上也不在表单上时,才关闭表单 if (!clickOnButton && !clickOnForm) { dateForm.classList.remove("active"); } });
如果你希望逻辑更简洁,也可以给触发按钮和表单分别加点击事件阻止冒泡,全局监听器直接关闭即可:
// 打开表单的事件加阻止冒泡 fulfillSetButton.addEventListener("click", function(e) { e.stopPropagation(); dateForm.classList.add("active"); }); // 表单内部点击阻止冒泡 dateForm.addEventListener("click", function(e) { e.stopPropagation(); }); // 全局点击直接关闭表单 html.addEventListener("click", function(){ dateForm.classList.remove("active"); });
内容的提问来源于stack exchange,提问作者Vlastimil Lisák
相关产品推荐
相关产品推荐

