当元素已经被移除时检测点击

Detect click when elements have already been removed

我试图检测是否在 DatePicker 控件上发生了点击,但我无法准确确定事件目标元素是否是 DatePicker 的一部分。

经过大量调试后,我意识到主要问题是 DatePicker 的各个部分与文档分离,因此它们根本不是任何元素的子元素。

感谢 this other question 我了解到原因是在切换月份时删除并替换了 DatePicker 的一部分,所以我从 event.target 获得的元素被分离了(它是已移除块的一部分)。

那么,如何判断这次点击是在我的控制范围内呢?我正在尝试以不可知论的方式写出正在使用的内容类型,尽管针对 DatePickers 的特定修复是可以的。

到目前为止,我所做的是检查我的元素是否包含 DatePicker,以及事件目标是否已分离。如果是这样,我假设点击发生在 DatePicker 上。这并不完美,因为页面上可能还有另一个 DatePicker。此外,被分离的事件目标不一定与 DatePicker 相关。

这是我目前所拥有的示例:

$(document).on("click", function (event) {
   const stuff = $("something");

   if (stuff.is($(event.target)))          
      return; // click was on stuff

   if ($(event.target).closest(stuff).length)
      return; // click was on descendents of stuff

   if (stuff.is(":active, :focus"))
      return; // stuff is active or focused

   if (stuff.find(":active, :focus").length)
      return; // a descendent of stuff is active or focused

   if (stuff.is(".hasDatepicker") || stuff.find(".hasDatepicker").length) {
      // stuff is or has a date picker
      if (!$(event.target).closest($(document)).length) {
         // event target is detached, and there's a date picker in stuff
         // so have to assume click was on stuff's date picker
         return;
      }
   }

   // click was not within stuff's elements
}

我不明白你的意思:
« DatePicker 的片段与文档分离,因此它们根本不是任何元素的子元素。»

这是错误的。您可以在页面中看到的所有元素都在 DOM 中(因此文档 "attached")。
但有时,不会很长时间,这里就是这种情况。

日期选择器元素在打开时创建并附加到 body
当它关闭时,它的元素都被删除了。

下面的代码检索被点击的元素,它 tagName、它的 class、它的 id 和它的 innerHTML
我什至在文档中重新创建了它们...
;)

它使用 delegation,因为@Roamer 在评论中根据需要正确提及。

$(document).on("mouseup",".ui-datepicker",function(e){
  var target = e.target;

  var tag = target.tagName.toLowerCase();
  var classes = target.className;
  var ID = target.id;
  var resultString = "<"+tag+" id='"+ID+"' class='"+classes+"'>"+target.innerHTML+"</"+tag+"><br>";
  console.log(resultString);

  var result = $(resultString);
  $("#result").append(result);
});

遗憾的是,我的示例中的 CSS 在 SO 代码段中效果不佳。 所以它在 CodePen.

我使用了 mouseup 事件,因为 click 不起作用...
可能是由于 return false 在 Datepicker 的某处。

你要找的大概是$(".selector").datepicker("widget")

Per the docs:

Returns a jQuery object containing the datepicker. This method does not accept any arguments.

Code examples: Invoke the widget method:

var widget = $( ".selector" ).datepicker( "widget" );

现在您可以从原始元素中获取实际的日期选择器 UI,您可以随心所欲地使用它,即检查点击是否在其上。

以下是我将如何使用上述方法解决此问题:

$(function() {

  $('#thedate').datepicker({
    dateFormat: 'dd-mm-yy',
    altField: '#thealtdate',
    altFormat: 'yy-mm-dd' 
  });

  $(document).on('mousedown',function(event) {
    // only evaluate if the click was NOT on the element or any of its descendants 
    if (!$(event.target).closest('#some-container').length && !$(event.target).is('#some-container')) {
      // now lets check for any elements in our container that have datepickers 
      var $contanier = $('#some-container');
      var $elementsWithDatePickers = $contanier.find('.hasDatepicker');
      var clickedChildDatePicker = false;
      $elementsWithDatePickers.each(function() {
        // for each datepicker found, check that the click was also not on it or any of its descendants
        var $widget = $(this).datepicker("widget");
        if ($(event.target).is($widget) || $(event.target).closest($widget[0]).length > 0) {
          clickedChildDatePicker = true;
          return false;
        }
      });
      if (!clickedChildDatePicker) {
        $contanier.hide();
      }
    }
  }) 
});
#other{
  background-color:#ccc; 
  padding: 45px;
}
#some-container{
  background-color:#fff;
  padding: 45px;
  
}
<link href="https://code.jquery.com/ui/1.8.21/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>


<div id="other"> 

<div id="some-container">
  Date :
  <div id="thedate">
  </div>
  <br /> 
</div>

  click here to hide container 
</div>