如何正确地监测元素外的点击事件?

22 浏览
0 Comments

如何正确地监测元素外的点击事件?

当我点击“添加新项目”按钮时,我希望弹出一个表单。

然后,如果我点击表单外部,我希望它隐藏。

为了显示/隐藏表单,我使用了ng-show指令。为了监视外部点击,我使用了第三方Angular指令angular-clickout。但是有一个问题 - 这个指令在页面加载时就开始工作,当我点击“添加新项目”按钮时,它立即调用我的关闭函数,这个函数将布尔属性设置为false,ng-show隐藏了表单...

HTML代码:


...省略的代码...

控制器代码:

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

0
0 Comments

通过这个问题的描述,可以看出它是关于如何正确地监听元素外部的点击事件。问题的出现是因为在JavaScript中事件的工作方式。当点击一个按钮时,会生成一个点击事件。事件首先从捕获阶段(自上而下)开始,从window开始,然后是div#content,最后是按钮。然后开始冒泡阶段(自下而上),首先是按钮,然后是div#content,最后是window。默认情况下,事件会附加到冒泡阶段,因此按钮会接收到点击事件,显示弹出窗口,然后窗口接收到点击事件并隐藏弹出窗口。这有点不便。解决这个问题的一种方法是使用stopPropagation来阻止事件冒泡。这种方法存在一些问题。例如,如果有两个按钮可以生成弹出窗口,点击button1然后button2不会关闭第一个弹出窗口,因为共享的父级永远不会收到任何点击事件。另一种解决方法是在捕获阶段添加弹出窗口的关闭。这种方法存在一个潜在问题,即在捕获阶段确定是否阻止点击事件关闭弹出窗口比较困难。另外,可以在捕获阶段标记事件,并延迟到冒泡阶段关闭弹出窗口(允许弹出窗口阻止关闭)。然而,这种方法与stopPropagation不兼容。任何具有stopPropagation的元素都会导致弹出窗口关闭失败,因为事件将不会再次冒泡。还可以让弹出窗口处理程序知道它应该忽略下一次点击。stopPropagation也有潜在的问题,例如当id#content上有stopPropagation时。还可以使用某种setTimeout技巧,延迟渲染弹出窗口,直到点击事件完成冒泡阶段。这种方法有效,但感觉像是一个糟糕的hack。从这个相当详细的答案中可以看出,这是一个我自己遇到过并且已经认真思考过的问题。我还不知道解决方法。每种解决方案似乎都有问题。然而,我已经决定stopPropagation是不好的。我之所以这样认为是因为stopPropagation破坏了模块化。子节点可以在没有父节点同意或知情的情况下影响父节点的行为,这似乎是一个问题。点击button1然后button2不会关闭第一个弹出窗口,因为点击事件被中止。这只在button2是button1的父节点的情况下才为真,这是不太可能的。请记住,用于检测元素外部点击的点击事件必须在某个父元素上,最好是尽可能高的位置。因此,如果它们共享这个父元素,第一个弹出窗口将不会关闭,这很可能是body。因此,我可以说这是非常可能的。clickout使用window作为共享父元素。详见:github.com/neoziro/angular-clickout/blob/master/angular-clickout.js

0
0 Comments

当我们需要在一个元素外部点击时执行某些操作时,我们可以使用事件监听来实现。但是,有时候我们需要防止事件冒泡到父元素,从而阻止父元素上的事件处理程序被通知到。

为了解决这个问题,我们可以在点击事件的处理程序中调用$event.stopPropagation()方法,阻止事件冒泡。下面是一个示例:


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

然而,这种方法存在一些问题。例如,如果我们有两个按钮可以弹出一个对话框,那么点击按钮1然后再点击按钮2时,第一个弹出框不会被关闭,因为共享的父元素从未接收到任何点击事件。在这种情况下,共享的父元素通常是窗口。为了解决这个问题,我们可以使用一个叫做"clickout"的模块。该模块的代码可以在这里找到。

有关这个问题的更多讨论,可以参考这里

0