【问题标题】:Detect click when elements have already been removed当元素已被删除时检测点击
【发布时间】:2017-07-16 03:03:06
【问题描述】:

我正在尝试检测是否在 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
}

【问题讨论】:

  • 你需要掌握jQuery的.on(),尤其是它的.on(events, selector, handler)形式。注意selector 的存在。鉴于您目前的理解水平,您应该几乎立即明白这一点。

标签: javascript jquery jquery-ui jquery-ui-datepicker


【解决方案1】:

你要找的可能是$(".selector").datepicker("widget")

Per the docs:

返回一个包含日期选择器的 jQuery 对象。 此方法不接受任何参数。

代码示例: 调用小部件方法:

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>

【讨论】:

  • 我有一个弹出窗口,我想在“点击离开”时隐藏它。我之前使用过focusout,但它不适用于日期选择器。所以我切换到$(document).click。然后我遇到了这个问题,事件中的元素已经从文档中删除,所以我实际上无法分辨它们是哪些元素或它们来自哪里。
  • 我知道这可能被视为一个“XY”问题,但在提出这个问题时,我对处理来自已删除元素的事件的这种特定情况更加好奇。
  • 不,这很完美,现在我了解了真正的问题,我可以提供更多帮助,请参阅我的更新 ;)
  • 应该可以,但是请注意,日期选择器元素没有从页面中删除。为了证明这一点,打开日期选择器,右键单击日期并选择“检查元素”,您应该会看到检查器中突出显示的 dom 元素。现在,返回并关闭日期选择器,注意所有元素仍然显示在检查器中,它们都只是隐藏了。另请注意,它们被附加到 body 标记中。所以元素就在那里,只是隐藏起来,而不是你期望在 dom 中找到它们的地方。
  • @Roamer-1888 好吧,太多了。我的代码实际上都在 TypeScript 中,一方面是我自己不断扩展的控制框架。我发布的是一个“最小、完整、可验证的例子”的尝试。它实际上与弹出窗口没有任何关系,问题实际上是“我如何绕过div DatePicker 在click 事件中的行为异常”。一个答案是,“使用input 或使用不同的事件”。
【解决方案2】:

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

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

Datepicker 元素在打开时创建并附加到 body
当它关闭时,它的元素全部被删除。

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

它使用delegation,正如@Roamer 在cmets 中正确提及的那样。

$(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 sn-p 中效果不佳。 所以它在CodePen

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

【讨论】:

  • DatePicker 的片段与文档分离,OP 的意思是实际的 datepicker 附加到文档正文而不是它绑定的元素的父级因此,原始元素和实际的 datepicker ui 不共享父元素
  • @DelightedD0D:您对问题的理解是正确的。但是引用句子的第二部分仍然是错误的:«它们根本不是任何元素的子元素。».
  • 哦,是的,完全同意。 OP 不太了解那里发生了什么,只是这不是他们所期望的
  • 唯一有意义的是“...主要问题是 DatePicker 的各个部分被删除并在将来的某个时候重新创建” ,因此丢失了附加的事件处理程序并需要委托。至少,我是这么看的。
  • @Roamer:我根据您的评论添加了一些解释;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-24
  • 2021-01-08
  • 2012-09-08
  • 2022-11-11
  • 2016-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多