“单击任意位置关闭”的原型最佳实践?

Prototype best practice for "click anywhere to close"?

提问人:Pekka 提问时间:12/17/2009 最后编辑:Rob WPekka 更新时间:1/31/2012 访问量:2318

问:

我发现自己经常遇到这样的情况:我在网页中打开一个元素(例如下拉菜单),如果用户单击页面上除元素本身以外的任何位置,我想要关闭该元素。

为了简单起见,我大部分时间都是自己编写代码,而不是使用一些下拉菜单类。

但是,我从未设法构建一个完全令人满意的实现:事件处理和冒泡在不同的浏览器中会以不同的方式工作,需要令人讨厌的解决方法,在某些情况下单击下拉按钮会在同一时刻开始关闭它,等等。

是否有基于原型的权威最佳实践来做到这一点?跨浏览器工作的东西 - IE6 是一个加分项,但不是必需的?

只是这个:

  • 单击按钮 - 打开一个元素 (例如,绝对定位的下拉菜单)。
  • 在元素内单击 - 元素保持打开状态。
  • 单击打开 elemen t 的按钮- 元素保持打开状态。
  • 单击页面上的任何其他位置 - 元素关闭。

我只需要事件处理部分的帮助,菜单的显示完全是次要的。

javascript 原型JS

评论

0赞 Skilldrick 12/17/2009
您在其他网站上是否有任何实践中您的要求示例?
0赞 Pekka 12/17/2009
好吧,从本质上讲,我正在寻找的是正常菜单的行为。您可以打开它,将鼠标移动到任何您想要的位置,但如果您单击其他任何地方,它将立即关闭。<select>

答:

1赞 Skilldrick 12/17/2009 #1

AFAIK,你需要制作一个窗口大小的不可见 div,把它放在当前元素后面,并添加一个点击事件。

评论

0赞 Pekka 12/17/2009
这是一种可行的方法,但我想避免它,因为这样你就不能立即点击页面上的其他内容。只需单击一下即可关闭元素。
0赞 Skilldrick 12/17/2009
因此,当您说“单击页面上的其他任何位置 - 元素关闭”时,您的意思是要执行单击该点的默认操作?
0赞 Skilldrick 12/17/2009
你可以做一些非常棘手的事情,比如计算出点击的位置,然后......不,这是一个非常糟糕的主意。
0赞 John Duff 12/17/2009 #2

只是大声思考,但您可以使用下拉列表上的模糊事件来隐藏它(当元素失去焦点时会触发模糊),或者另一个想法可能是在下拉列表打开时将单击事件附加到隐藏下拉列表的文档对象。事件通过其容器传播,因此它最终应该出现在文档对象中。当单击下拉列表时,可能需要对事件调用 preventPropegation,以便它不会进入附加到文档的处理程序。

评论

0赞 Pekka 12/17/2009
好主意,但元素在打开时不需要聚焦。不过,我正在寻找事件传播问题的工作解决方案,只是与 onClick 有关。
0赞 nils petersohn 12/17/2009 #3

也许您可以计算 clickevent 的 Position (X,Y),并将其与所需容器的 cumulativeOffset (cumulativeScrollOffset) + [el.width|el.height] 进行比较。

Event.observe(window, 'click', function(e) {

  var el = $('el')

  if( el.cumulativeOffset[0] < e.Event.pointerX(e) ...  )

});

<div id="el" style="position:absolute;width:100px;height:100px;background-color:#00F;top:100px;left:300px;">

</div>

评论

0赞 Pekka 12/17/2009
创意,但我认为有太多可能出错的事情。我认为它需要由事件驱动才能真正安全。
4赞 Tomasz Durka 12/17/2009 #4
Event.observe(document, 'click', function (event) {
  switch (event.element().id) {
    case 'example_id':
      // do different stuff depending on element clicked
      // ofc u don't need to pass id, u can simply throw an element itself
      break;
    default:
      // do close action
      break;
  }
  // also check Event.findElement();
});

您还可以将特定类添加到您不想触发关闭操作的项中,并在其中进行检查

if (!event.element().hasClassName('dont_close'))   
  Element.remove(selectDOMElement);
2赞 blq 1/31/2012 #5

我猜打开按钮在菜单中。

$('openbutton').observe('click' function(event) {
    var menu = $('openbutton').up();

    if (menu.hasClassName('collapsed')) {

        menu.removeClassName('collapsed');
        menu.addClassName('expanded');

        document.observe('click', function (event) {
            if(!event.target.descendantOf(menu)) {
                menu.addClassName('collapsed');
                menu.removeClassName('expanded');
            }
        });

    } else {
        menu.addClassName('collapsed');
        menu.removeClassName('expanded');
    }
});