2017-01-23 53 views
0

我有了一个链接列表,它可以打开和关闭小部件:当使用模糊与超时实现点击外关闭 - 时间间隔有时太短

<div class="widget"> 
    <input class="focuser"> 
    <a href="javascript:;">View options</a> 
    <ul> 
     <li>Option 1</li> 
     <li>Option 1</li> 
    </ul> 
</div> 

所以,当我点击View options - 列表出现,当点击任何选项 - 做东西并关闭选项列表。

而且我需要有click-outside-close功能 - 当用户在关闭列表之外的任何地方单击时。

我通过在显示选项时关注一个不可见的输入以及在输入的blur上实现了这一点 - 在某些超时后隐藏选项。这样:

  1. 当用户在外面点击 - 模糊超时用完 - 隐藏选项。
  2. 如果用户点击任何选项 - 清除超时,隐藏选项&做 的东西。

现在的问题是,有时超时会在点击之前结束。我将超时间隔增加到了200毫秒,但它仍然不是100%确定的,而且 - 用户在关闭选项列表之前看到延迟。

任何想法如何解决和/或改善?

编辑:JavaScript代码的

这是简化版本:

CartSidebar.DwCustomSelect = Ember.View.extend({ 

    blurTimeout: false, 

    focusOut: function(e) { 
     if (e.target.className == 'focuser') { 
      var self = this; 
      this.blurTimeout = setTimeout(function() { 
       clearTimeout(self.blurTimeout); 
       $(self.element).removeClass('opened'); // hide options .. 
      }, 180); 
     } 
    }, 

    click: function(e) { 

     var clickedElement = e.target; 

     clearTimeout(this.blurTimeout); 
     if (clickedElement.tagName.toLowerCase() == 'li') { 
      $(this.element).removeClass('opened'); // hide options .. 
      doStuff(); 
     } 
    } 
} 

编辑2:

我创建了一个plunker,这样你就可以在行动中看到它:

https://plnkr.co/edit/boA6yC0sEbLAZU9tjyso?p=preview

(我的超时时间太短,所以你看到了问题。但即使增加间隔 - 您将看到focusOutclick之前触发。)

+0

的jsbin为什么你需要超时?为什么不在列表之外单击后立即隐藏列表? –

+0

就像@MattSpinks说的,摆脱'setTimeout'。如果你坚持使用'setTimeout'来延迟,那么发布你的代码来看看问题在哪里。 –

+0

因为在这种情况下,您点击选项 - 序列将是“输入模糊” - “隐藏选项” - “点击” - 但选项不会在那里,所以点击触发选项下方的元素。 –

回答

0

超时事件是一个选项。但是你必须定义一个很大的时间间隔,因为它取决于浏览器处理所有事情的速度。它会工作99.99%的时间,但它不是防弹的,正如你所说的。

其他诀窍是聆听整个事物的模糊。如果您将tabindex属性指定给某个元素,它将接收焦点事件。如果你设置了tabindex="0"它会得到一个自动索引,你不必担心它。

因此,不要聆听input的模糊,而要聆听div.widget的模糊。当焦点从输入到链接或li s时,它仍然在widget的焦点内,并且blur事件不会触发。

+0

我试过你的建议,但是当我点击列表中的一个选项时 - 父元素失去了焦点,尽管它有'tabindex'。我调试,看到焦点转到点击元素 - 下拉选项。 –

+0

是的,焦点改变了,但'.widget' *的'blur'(或'focusOut',对于这件事情是相同的)事件*不应该被触发(输入的'模糊'将会触发)。你只需要听听正确的元素事件。如果这不是问题,请发布你的代码来检查它。 – Gabriel

+0

我今天早些时候编辑了我的问题,并添加了我的JS代码。没关系,或者你想看看别的东西? :) –

1

如果你想要一个功能,当用户点击除div之外的任何地方时,你需要隐藏你的div,然后你可以添加一个点击监听器到整个文档中,用代码来隐藏div。

var a = document.querySelector("a"); 
var ul = document.querySelector("ul"); 
a.addEventListener('click', function(e){ 
e.stopPropagation(); 
if(ul.classList.contains('show')){ 
    ul.classList.remove('show'); 
    ul.classList.add('hide'); 
}else{ 
    ul.classList.remove('hide'); 
    ul.classList.add('show'); 
} 
}); 

document.addEventListener('click', function(){ 
    ul.classList.remove('show'); 
    ul.classList.add('hide'); 
}); 

对于细节例如检查以下

http://jsbin.com/mamexev/edit?html,css,js,output

+0

我也在想这样的解决方案 - 全局听文件'click' - 但这些小部件实际上是一个'Ember'视图,并且它有它自己的'click'处理程序,这是我应该使用的。该监听器绑定到小部件的顶层元素。这是我检查是否单击某个选项并清除输入超时的位置。 –

+0

您是否可以使用当前写入的JavaScript代码更新您的问题以模糊并隐藏列表? – Sam

+0

当然。我只是做:) –