如何正确观察元素外的点击?

时间:2015-05-04 15:23:19

标签: javascript angularjs angularjs-ng-click ng-show

当我点击"添加新项目"按钮我想要显示一个弹出窗体。 然后,如果我在此表单外单击,我希望它隐藏自己。 要显示/隐藏表单,我使用ng-show指令。要注意外部点击,我使用第三方Angular指令angular-clickout但是有一个问题 - 这个指令开始处理页面加载,当我点击"添加新项目"按钮它立即调用我的关闭函数,然后将布尔属性设置为false值,ng-show隐藏一个表单...

HTML:

<button ng-click="vm.displayDialogAddNewItem()>Add New Item</button>
<div class="new-item-dialog" 
     ng-show="vm.dialogAddNewItemIsVisible"     
     click-out="vm.hideDialogAddNewItem()">
    ... omitted code ...
</div>

控制器代码:

vm.displayDialogAddNewItem = function() {
    vm.dialogAddNewItemIsVisible = true;
};

vm.hideDialogAddNewItem = function() {
    vm.dialogAddNewItemIsVisible = false;
};

2 个答案:

答案 0 :(得分:1)

您需要阻止事件冒泡DOM树,从而阻止父处理程序(在关闭模式的窗口上)被通知事件。

<!-- Pass the $event to the handler -->
<button ng-click="vm.displayDialogAddNewItem($event)>Add New Item</button>

JS

vm.displayDialogAddNewItem = function($event) {
    vm.dialogAddNewItemIsVisible = true;
    $event.stopPropagation(); // Stop bubbling up.
};

答案 1 :(得分:0)

这与事件在JavaScript中的工作方式有关。

假设你有这个HTML:

<div id="content">
  <input type="button />
</div>

如果单击该按钮,则会生成单击事件。该事件将在捕获阶段(自上而下)开始,从window开始,然后是div#content,然后是按钮。然后冒泡阶段开始(自下而上),首先是按钮,然后是div#content然后是window

默认情况下事件会附加到冒泡阶段,因此您的按钮会收到click事件,显示弹出窗口,然后窗口会收到点击并隐藏弹出窗口。这有点不方便。

解决此问题的一种方法是使用stopPropagation来阻止事件冒泡。这种方法存在一些问题。例如,如果你有两个可以产生弹出窗口的按钮。单击button1然后button2将不会关闭第一个弹出窗口,因为共享父节点从未看到任何单击事件。

另一种解决方案是在捕获阶段添加弹出窗口关闭。当你想阻止弹出窗口点击关闭弹出窗口时,会出现一个潜在的问题。在捕获阶段难以确定该块。另一个解决方案是在捕获阶段标记事件,并延迟关闭到泡沫阶段(允许弹出窗口抛出一个块)。然而,这与stopPropagation不太匹配。任何带有stopPropagation的元素都会导致弹出窗口更接近失败,因为事件永远不会再冒出来。

另一种方法是让弹出处理程序知道它应该忽略下一次单击。 stopPropagation再次有可能在这里造成伤害。例如,当id#content上有stopPropagation时。

你还可以使用某种setTimeout技巧来延迟弹出窗口的渲染,直到click事件完成它的冒泡阶段。这有效,但感觉就像一个可怕的黑客。

正如你从这个相当精细的答案中看到的那样,这是我遇到的一个问题,并且已经考虑了很多。我还不知道解决方案。每个解决方案似乎都存在问题。我已经决定 stopPropagation不好。我的理由是stopPropagation打破了模块性。子节点可以在没有父母同意或知情的情况下影响父节点的行为,这似乎是一个问题。