简体   繁体   English

$(event.target).closest()。隐藏div的长度并不总是有效。任何替代品?

[英]$(event.target).closest().length to hide div doesn't always work. Any alternatives?

I use $(event.target).closest("#divID").length to hide a div when the user clicks outside of it but in the case that the div is visible and I click on a date (datepicker) it won't hide the div . 我使用$(event.target).closest("#divID").length来隐藏div当用户点击它时,但是如果div是可见的,我点击日期(datepicker)它赢了' t隐藏div

Also if I click on a <select> sometimes it hides it sometimes it doesn't. 此外,如果我点击<select>有时它隐藏它有时它不会。

Is there a better solution to hide a div when something else is clicked? 有什么更好的解决方案可以在点击其他内容时隐藏div吗?

Is my implementation wrong? 我的实施错了吗?

ps: #log_in is the login button, #log_in_form is the form that I want to hide on outside click and #log_in_container is the div that contains #log_in and and #log_in_form ps: #log_in是登录按钮, #log_in_form是我要在外部点击时隐藏的form#log_in_container是包含#log_in#log_in_form的div

UPDATE: I just noticed that the disappearance isn't the same on windows 10 and linux ubuntu 16.04. 更新:我刚注意到在Windows 10和Linux ubuntu 16.04上的消失是不一样的。 On a pc with windows 10 using google chrome the form disappears on the first click i do on a select(thats the desirable functionality) but still doesn't disappear if i choose a date. 在使用谷歌浏览器使用谷歌浏览器的PC上,表格在第一次点击时消失了(这是理想的功能),但如果我选择日期,它仍然不会消失。 While on linux ubuntu 16.04 on google chrome it is as i described above (doesn't disappear on date choice and also doesn't disappear on the first click you do on select) 虽然在谷歌Chrome上的Linux ubuntu 16.04上,它就像我上面描述的那样(在选择日期时不会消失,并且在你选择的第一次点击时也不会消失)

Example based on Andrei's answer with snippet 示例基于Andrei对代码段的回答

 $(document).on('click', function(e){ if($(e.target).closest('#log_in').is('#log_in')) { $('#log_in_form').fadeIn(); } else if(!$(e.target).closest('#log_in_container').is('#log_in_container')) { $('#log_in_form').fadeOut(); } }) 
 #log_in_container{ display:inline-block; width:122px; height:58px; margin-left:60px; background-color:gray; } #log_in{ display:block; width:120px; height:28px; text-align: center; border: 1px solid red; font-size:16px; background-color:yellow; vertical-align: top; } #log_in_form{ display:none; position:absolute; width:120px; height:28px; text-align: center; background-color: green; border: 1px solid blue; } .type{ display:inline-block; width:120px; height:30px; text-align: center; border: 1px solid red; font-size:16px; } 
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <!-- ~~~~~~~~~~~~~~~Date picker ~~~~~~~~~~~~~~~ --> <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> <script src="https://code.jquery.com/jquery-1.12.4.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <script> $( function() { $( "#datepicker" ).datepicker(); }); </script> <title></title> </head> <body> <select class="type"> <option value="null" disabled="disabled" selected="selected"><p style="color:gray;">Select hero</p></option> <option value="0">Spiderman</option> <option value="1">Iron man</option> <option value="2">Deadpool</option> </select> <select class="type"> <option value="null" disabled="disabled" selected="selected"><p style="color:gray;">Select food</p></option> <option value="0">Kebab</option> <option value="1">Mousaka</option> <option value="2">Noodles</option> </select> <div id="log_in_container"> <div id="log_in">Log_In_button</div> <div id ="log_in_form">login_form</div> </div> <div id="datepicker"></div> </body> </html> 

In the above snippet if you click at Log_in_button the Log_in_form appears. 在上面的代码片段中,如果单击Log_in_button,则会显示Log_in_form。 If then you click on a date it doesn't disappear, then click on a select the Log_in_form still doesn't disappear, after that click on the next select the Log_in_form is still visible. 如果然后你点击它不会消失的日期,然后点击一个选择Log_in_form仍然不会消失,之后点击下一步选择Log_in_form仍然可见。 I would like to make it so that it disappears in these occasions (like select pop up does). 我想这样做,以便它在这些场合消失(如选择弹出窗口)。 Is this possible? 这可能吗?

jQuery works only with event bubbling (the event starts at the target element and works up the DOM tree, raising click events until it reaches the top level document ). jQuery仅适用于事件冒泡(事件从目标元素开始并处理 DOM树,引发单击事件直到它到达顶级document )。 The potential issue with this, as you can see with the ui-datepicker , is that elements can cancel the bubbling by using event.stopPropagation() , and the document never gets it. 正如您在ui-datepicker看到的那样,潜在的问题是元素可以通过使用event.stopPropagation()取消冒泡,并且document永远不会得到它。

Instead you need to use raw Javascript event capturing instead, where the top-level element captures the event happening and passes it down the DOM tree. 相反,你需要使用原始的Javascript事件捕获代替,其中顶层元素捕获事件发生并传递下来的DOM树。

The diagram on the W3C site explains the capture and bubble flow nicely, and see this question for more details and cross-browser implementation. W3C网站图表很好地解释了捕获和气泡流,并查看了这个问题以获取更多详细信息和跨浏览器实现。

The change required to your code is minimal, you are just using document.addEventListener instead of $(document).on : 您的代码所需的更改很少,您只需使用document.addEventListener而不是$(document).on

 document.addEventListener("click", function(e){ if($(e.target).closest('#log_in').is('#log_in')) { $('#log_in_form').fadeIn(); } else if(!$(e.target).closest('#log_in_container').is('#log_in_container')) { $('#log_in_form').fadeOut(); } }, true); 
 #log_in_container{ display:inline-block; width:122px; height:58px; margin-left:60px; background-color:gray; } #log_in{ display:block; width:120px; height:28px; text-align: center; border: 1px solid red; font-size:16px; background-color:yellow; vertical-align: top; } #log_in_form{ display:none; position:absolute; width:120px; height:28px; text-align: center; background-color: green; border: 1px solid blue; } .type{ display:inline-block; width:120px; height:30px; text-align: center; border: 1px solid red; font-size:16px; } 
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <!-- ~~~~~~~~~~~~~~~Date picker ~~~~~~~~~~~~~~~ --> <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> <script src="https://code.jquery.com/jquery-1.12.4.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <script> $( function() { $( "#datepicker" ).datepicker(); }); </script> <title></title> </head> <body> <select class="type"> <option value="null" disabled="disabled" selected="selected"><p style="color:gray;">Select hero</p></option> <option value="0">Spiderman</option> <option value="1">Iron man</option> <option value="2">Deadpool</option> </select> <select class="type"> <option value="null" disabled="disabled" selected="selected"><p style="color:gray;">Select food</p></option> <option value="0">Kebab</option> <option value="1">Mousaka</option> <option value="2">Noodles</option> </select> <div id="log_in_container"> <div id="log_in">Log_In_button</div> <div id ="log_in_form">login_form</div> </div> <div id="datepicker"></div> </body> </html> 

As you mentioned previously, the initial <select> does work in Chrome on Windows, but not Chrome on Linux. 正如您之前提到的,最初的<select>在Windows上的Chrome中有效,但在Linux上却无效。 Browsers often hand off rendering of form controls to the OS for visual consistency, but this can introduce inconsistency in behaviour. 浏览器通常会将表单控件的呈现交给操作系统以实现视觉一致性,但这会导致行为不一致。 <select> s are probably the most inconsistent of the base form controls, because of their added complexity. <select> s可能是基本表单控件中最不一致的,因为它们增加了复杂性。 This question demonstrates this issue, particularly: 这个问题证明了这个问题,特别是:

Chrome 19 on Linux: First mouse click expands options [click event not triggered], subsequent click on either the still-present select, or the options, triggers click event. Linux上的Chrome 19:首先鼠标单击展开选项[单击事件未触发],然后单击仍然存在的选项或选项,触发单击事件。

As this is a browser behaviour which you don't have control over, I don't think there is any way around it - you can only handle the events it fires. 由于这是一个你无法控制的浏览器行为,我认为没有办法解决它 - 你只能处理它触发的事件。 If the event is not fired by the browser, you can't react to it. 如果浏览器未触发该事件,则无法对其做出反应。

You can simply use mouseup event instead of click which will work even on date click. 您只需使用mouseup事件而不是click在日期点击时使用。

 $(document).on('mouseup', function(e){ if($(e.target).closest('#log_in').is('#log_in')) { $('#log_in_form').fadeIn(); } else if(!$(e.target).closest('#log_in_container').is('#log_in_container')) { $('#log_in_form').fadeOut(); } }) 
 #log_in_container{ display:inline-block; width:122px; height:58px; margin-left:60px; background-color:gray; } #log_in{ display:block; width:120px; height:28px; text-align: center; border: 1px solid red; font-size:16px; background-color:yellow; vertical-align: top; } #log_in_form{ display:none; position:absolute; width:120px; height:28px; text-align: center; background-color: green; border: 1px solid blue; } .type{ display:inline-block; width:120px; height:30px; text-align: center; border: 1px solid red; font-size:16px; } 
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <!-- ~~~~~~~~~~~~~~~Date picker ~~~~~~~~~~~~~~~ --> <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> <script src="https://code.jquery.com/jquery-1.12.4.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <script> $( function() { $( "#datepicker" ).datepicker(); }); </script> <title></title> </head> <body> <select class="type"> <option value="null" disabled="disabled" selected="selected"><p style="color:gray;">Select hero</p></option> <option value="0">Spiderman</option> <option value="1">Iron man</option> <option value="2">Deadpool</option> </select> <select class="type"> <option value="null" disabled="disabled" selected="selected"><p style="color:gray;">Select food</p></option> <option value="0">Kebab</option> <option value="1">Mousaka</option> <option value="2">Noodles</option> </select> <div id="log_in_container"> <div id="log_in">Log_In_button</div> <div id ="log_in_form">login_form</div> </div> <div id="datepicker"></div> </body> </html> 

Your code is working except on dateoicker <td> . 除了dateoicker <td>之外,您的代码正在运行。 this is really weird 这真的很奇怪

But we can still hack this using onSelect method from jQuery ui datepicker . 但是我们仍然可以使用jQuery ui datepicker中的onSelect方法来破解它。

 $(document).on('click', function(e){ if($(e.target).closest('#log_in').is('#log_in')) { $('#log_in_form').fadeIn(); } else if(!$(e.target).closest('#log_in_container').is('#log_in_container')) { $('#log_in_form').fadeOut(); } }) 
 #log_in_container{ display:inline-block; width:122px; height:58px; margin-left:60px; background-color:gray; } #log_in{ display:block; width:120px; height:28px; text-align: center; border: 1px solid red; font-size:16px; background-color:yellow; vertical-align: top; } #log_in_form{ display:none; position:absolute; width:120px; height:28px; text-align: center; background-color: green; border: 1px solid blue; } .type{ display:inline-block; width:120px; height:30px; text-align: center; border: 1px solid red; font-size:16px; } 
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <!-- ~~~~~~~~~~~~~~~Date picker ~~~~~~~~~~~~~~~ --> <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> <script src="https://code.jquery.com/jquery-1.12.4.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <script> $( function() { $( "#datepicker" ).datepicker({ onSelect: function(i, e){ $('#log_in_form').fadeOut(); } }); }); </script> <title></title> </head> <body> <select class="type"> <option value="null" disabled="disabled" selected="selected"><p style="color:gray;">Select hero</p></option> <option value="0">Spiderman</option> <option value="1">Iron man</option> <option value="2">Deadpool</option> </select> <select class="type"> <option value="null" disabled="disabled" selected="selected"><p style="color:gray;">Select food</p></option> <option value="0">Kebab</option> <option value="1">Mousaka</option> <option value="2">Noodles</option> </select> <div id="log_in_container"> <div id="log_in">Log_In_button</div> <div id ="log_in_form">login_form</div> </div> <div id="datepicker"></div> </body> </html> 

I have a suggestion to use the event mousedown instead of click and also to check whether the click happened inside the log in wrapper like this 我有一个建议是使用事件mousedown而不是click并检查点击是否发生在日志包装中这样

$(e.target).parents().has($('#log_in_container')).length

the entire document ready would look like this 准备好的整个文件看起来像这样

$(document).on('mousedown', function(e){
    if($(e.target).closest('#log_in').is('#log_in'))
    {
      $('#log_in_form').fadeIn();
    }
    else if($(e.target).parents().has($('#log_in_container')).length)
    {
      $('#log_in_form').fadeOut();
    }
})

Why don't you use the onSelect event of the datepicker and trigger the click that you have bound to the document manually, as it does not seem to be triggered when you click on the dates inside the datepicker , no need to change anything regarding events or writing a separate logic inside the onSelect , just add any more logic if you want inside the .on('click') and trigger it just add 2 lines of your code and keep everything as is. 你为什么不使用onSelect的事件datepicker ,并触发你的点击bounddocument手动,因为它似乎并没有当你点击里面的日期被触发datepicker ,没有必要改变对任何事件或者在onSelect编写一个单独的逻辑,只需在.on('click')添加更多逻辑并触发它只需添加2行代码并保持原样。

You just need to change your datepicker initialization like below 您只需要更改datepicker初始化,如下所示

$("#datepicker").datepicker({
    onSelect: function (date, obj) {
        $(document).trigger('click')
    }
});

See the demo below 请参阅下面的演示

 $(document).on('click', function(e) { if ($(e.target).closest('#log_in').is('#log_in')) { $('#log_in_form').fadeIn(); } else if (!$(e.target).closest('#log_in_container').is('#log_in_container')) { $('#log_in_form').fadeOut(); } }) 
 #log_in_container { display: inline-block; width: 122px; height: 58px; margin-left: 60px; background-color: gray; } #log_in { display: block; width: 120px; height: 28px; text-align: center; border: 1px solid red; font-size: 16px; background-color: yellow; vertical-align: top; } #log_in_form { display: none; position: absolute; width: 120px; height: 28px; text-align: center; background-color: green; border: 1px solid blue; } .type { display: inline-block; width: 120px; height: 30px; text-align: center; border: 1px solid red; font-size: 16px; } 
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <!-- ~~~~~~~~~~~~~~~Date picker ~~~~~~~~~~~~~~~ --> <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> <script src="https://code.jquery.com/jquery-1.12.4.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <script> $(function() { $("#datepicker").datepicker({ onSelect: function(date, obj) { $(document).trigger('click') } }); }); </script> <title></title> </head> <body> <select class="type"> <option value="null" disabled="disabled" selected="selected"><p style="color:gray;">Select hero</p></option> <option value="0">Spiderman</option> <option value="1">Iron man</option> <option value="2">Deadpool</option> </select> <select class="type"> <option value="null" disabled="disabled" selected="selected"><p style="color:gray;">Select food</p></option> <option value="0">Kebab</option> <option value="1">Mousaka</option> <option value="2">Noodles</option> </select> <div id="log_in_container"> <div id="log_in">Log_In_button</div> <div id="log_in_form">login_form</div> </div> <div id="datepicker"></div> </body> </html> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM