单击外部时隐藏Angular UI Bootstrap弹出窗口

Posted

技术标签:

【中文标题】单击外部时隐藏Angular UI Bootstrap弹出窗口【英文标题】:Hide Angular UI Bootstrap popover when clicking outside of it 【发布时间】:2015-08-11 07:50:23 【问题描述】:

当我单击documentbody 上不是弹出框的任意位置时,我正在尝试手动关闭引导弹出框以使其关闭。

我发现最接近的方法是创建一个指令 (found this answer),但如果变量为 truefalse,这是用于手动触发.

如果我点击任何不是弹出框的东西,谁能帮我弄清楚如何让它关闭?

我不介意使用 jQuery $(document).click(function(e)); 我只是不知道如何调用关闭。

<div id="new_button" popover-template="plusButtonURL" popover-placement="right" popover-append-to-body="true" popover-animation="false">+</div>

通常popover-trigger="focus" 可以解决问题,但是我的弹出框包含需要单击的内容。如果我使用 focus 触发器,我的弹出框内有一个 ng-click 会被忽略,所以我正在寻找一种不那么传统的方法来解决这个问题。

【问题讨论】:

能否提供一个 plunkr 或 jsfiddle 供我们即插即用? @PatrickMotard here you go angular-ui.github.io/bootstrap 【参考方案1】:

更新:在 1.0 版本中,我们添加了一个名为 outsideClick 的新触发器,当用户在弹出框或工具提示之外点击时,它会自动关闭弹出框或工具提示。

从 0.14.0 版本开始,我们添加了通过tooltip-is-openpopover-is-open 属性以编程方式控制工具提示/弹出框何时打开或关闭的功能。

【讨论】:

有没有一个例子说明如何使用popover-is-open在任何地方点击弹出框时关闭它? @MattDionis 如果popover-is-open 的值为真,则对话框将打开。例如,您可以通过范围变量来控制它。 @MattDionis,我们已添加此功能。它目前在 master 中可用,并且针对 1.0 版本。有一个名为 outsideClick 的新触发器。 有人应该将此添加到文档中...我终于在源代码中找到了它:( @r0m4n,你说的“这个”是什么意思?它在我们的文档中。在angular-ui.github.io/bootstrap/#/popover 和angular-ui.github.io/bootstrap/#/tooltip 中。【参考方案2】:

从 Angular UI Bootstrap 1.0.0 开始,有一个用于工具提示和弹出框的新 outsideClick 触发器(在 this pull request 中引入。在 Angular UI Bootstrap 2.0.0 中,popover-trigger 已修改为使用角度表达式( Changelog),所以值必须用引号括起来。这段代码适用于当前版本的 angular-ui:

<div id="new_button" uib-popover-template="plusButtonURL" popover-trigger="'outsideClick'"
    popover-placement="right" popover-append-to-body="true" popover-animation="false">+</div>

此代码适用于旧版本的 Angular UI Bootstrap(2.0.0 之前):

<div id="new_button" uib-popover-template="plusButtonURL" popover-trigger="outsideClick"
    popover-placement="right" popover-append-to-body="true" popover-animation="false">+</div>

【讨论】:

在 2015 年还不确定,但现在触发器是一个角度表达式,所以它必须是 popover-trigger="'outsideClick'"【参考方案3】:

已编辑:

Plunker Demo

这是它的工作原理(仍然很长且详尽的解释):

    创建一个允许您定位触发器元素的自定义指令。 创建一个自定义指令,添加到正文中,并在单击时找到触发元素并触发自定义事件。

创建一个自定义指令来定位触发器元素:

您需要从打开弹出框的元素中触发自定义事件处理程序(在演示中这是按钮)。挑战在于弹出框作为同级元素附加到该元素,我始终认为当您遍历 DOM 并期望它具有特定结构时,事情有更大的破坏潜力。有几种方法可以定位触发元素,但我的方法是在单击元素时为元素添加一个唯一的类名(我选择“触发”)。在这种情况下,一次只能打开一个弹出框,因此使用类名是安全的,但您可以根据自己的喜好进行修改。

自定义指令

app.directive('popoverElem', function()
  return
    link: function(scope, element, attrs) 
      element.on('click', function()
        element.addClass('trigger');
      );
    
  
);

应用于按钮

<button popover-template="dynamicPopover.templateUrl" popover-title="dynamicPopover.title" class="btn btn-default" popover-elem>Popover With Template</button>

为文档正文(或任何其他元素)创建自定义指令以触发弹出框关闭:

最后一部分是创建一个自定义指令,该指令将定位触发元素并触发自定义事件以在单击应用它的元素时关闭弹出框。当然,您必须从“触发器”元素中排除初始点击事件,以及您想要在弹出框内部与之交互的任何元素。因此,我添加了一个名为 exclude-class 的属性,以便您可以定义一个类,您可以将其添加到应忽略点击事件的元素(不会导致弹出框关闭)。

为了清理,当事件处理程序被触发时,我们删除添加到触发器元素的触发器类。

app.directive('popoverClose', function($timeout)
  return
    scope: 
      excludeClass: '@'
    ,
    link: function(scope, element, attrs) 
      var trigger = document.getElementsByClassName('trigger');

      function closeTrigger(i) 
        $timeout(function() 
          angular.element(trigger[0]).triggerHandler('click').removeClass('trigger'); 
        );
      

      element.on('click', function(event)
        var etarget = angular.element(event.target);
        var tlength = trigger.length;
        if(!etarget.hasClass('trigger') && !etarget.hasClass(scope.excludeClass)) 
          for(var i=0; i<tlength; i++) 
            closeTrigger(i)
          
        
      );
    
  ;
);

我将它添加到 body 标记中,以便整个页面* 充当弹出框的可关闭背景:

<body popover-close exclude-class="exclude">

而且,我在弹出框的输入中添加了排除类:

<input type="text" ng-model="dynamicPopover.title" class="form-control exclude">

所以,有一些调整和陷阱,但我会留给你:

    您应该在 popover-close 指令的链接函数中设置一个默认排除类,以防未定义。 您需要注意 popover-close 指令是元素绑定的,因此如果您删除我在 html 和 body 元素上设置的样式以赋予它们 100% 的高度,您的视口中可能会出现“死区”,如果你的内容没有填满它。

在 Chrome、Firefox 和 Safari 中测试。

【讨论】:

哇,这很全面。这次真是万分感谢。我的页面上有很多按钮,所以在与页面上的任何其他元素交互之前必须隐藏弹出框(点击背景)有点糟糕。有没有办法避免背景?用户体验会更好,只需在除弹出框之外的任何地方单击鼠标即可隐藏。无论如何,这是一个很好的答案,我真的很感激它!谢谢! 完全有效的点。是的,我可以对此进行调整,以便您可以将 popoverBackdrop 添加到 body 标记中。给我几分钟,我会更新。 我不得不将我的代码更改为this,因为我假设的弹出框是动态加载的。但这最终奏效了。谢谢@jme11 只是给阅读此链的人们的注意事项。我们在 0.14.0 中添加了一项新功能,可让您以编程方式打开/关闭工具提示和弹出框。请参阅我在此 SO 项目中的答案。 @JackMalkovich 当您单击按钮打开,然后再次单击按钮关闭弹出框,单击之后的任何其他位置将打开弹出框。在这个Plunk 中,我提供了一个简单的修复,唯一的变化是(element.hasClass('trigger'))? element.removeClass('trigger'): element.addClass('trigger');popoverDirective【参考方案4】:

popover-trigger="'outsideClick'" 这将完美运行。

popover-trigger="outsideClick"这不会。

我花了 1 天时间弄清楚为什么它不适合我。

这是因为他们使用此代码进行检查,"if (trigger === 'outsideClick')"

这是由于强类型检查,我们需要将其作为 String

传递

【讨论】:

这个“陷阱”让我...我假设一个神秘的事件处理程序在它传播之前正在吃掉这个事件。添加了单引号和作品【参考方案5】:

有一个名为popover-trigger 的属性,您可以将属性focus 分配给该属性。

<button 
      popover-placement="right" 
      popover="On the Right!" 
      popover-trigger="focus" 
      class="btn btn-default">
   Right
</button>

这就是诀窍! :)

编辑: 要允许单击工具提示而不触发焦点丢失,请考虑一种方法similar to this

如果您希望它以角度工作,请尝试创建自己的触发器定义。关于如何做到这一点的建议可以是found here。

【讨论】:

这是我想要的,但它似乎在我使用的浏览器中不起作用(最新的 Safari OS X)。焦点似乎只在 input 文本上跨浏览器工作 我有一个 browserStack 帐户。让我在 Safari OS X (Yosemite?) 中试一试以确认。 我很感激,是的,优胜美地。听说firefox也有这个问题。 是的,在 firefox 和 safari 中都提交了有关此问题的票证。我正在寻找解决办法。如果您不包括 class="btn" 这对我们来说不是这种情况,则已关闭票证中提到的修复与它不起作用有关。 这是我正在寻找的方法,但 .popover('hide') 不适用于 angular bootstrap【参考方案6】:

你要找的是

<button
      popover-trigger="outsideClick" 
      class="btn btn-default">
   Right
</button>

来自文档 - outsideClick 触发器将导致弹出框在点击时切换,并在点击其他任何内容时隐藏。

【讨论】:

工作正常 :) 谢谢。 这是正确的答案,因为 angular-ui 在他们的库中本地实现了这个。不再需要任何技巧和变通方法。 popover-trigger="'outsideClick'" 需要单引号 这个答案被低估了,值得更多的支持。【参考方案7】:

你可以使用:

标记

<div ng-app="Module">
    <div ng-controller="formController">
        <button uib-popover-template="dynamicPopover.templateUrl" popover-trigger="focus" 
          popover-placement="left" type="button" class="btn btn-default">
             Popover With Template
        </button>

        <script type="text/ng-template" id="myPopoverTemplate.html">
            <div>
                <span>prasad!!</span>
            </div>
        </script>
    </div>
</div>

Javascript

<script type="text/javascript">
    var app = angular.module("Module", ['ui.bootstrap']);
    app.controller("formController", ['$scope', function($scope) 
        $scope.dynamicPopover = 
            templateUrl: 'myPopoverTemplate.html'
        ;
    ]);
</script>

【讨论】:

【参考方案8】:

我遇到了同样的问题,popover-trigger="'outsideClick'" 为我工作。有趣的是文档没有说明这个问题。

【讨论】:

【参考方案9】:

'$uibTooltipProvider' setTriggers 方法中的 'outsideClick' 选项怎么样。文档说“outsideClick 触发器将导致工具提示在单击时切换,并在单击其他任何内容时隐藏。” Documentation

【讨论】:

【参考方案10】:

Angular boostrap ui 新版本 1.x 具有外部点击功能。将其升级到新版本。

<button uib-popover-template="updatePassword.templateUrl" popover-title="Update Password" popover-trigger="outsideClick" popover-placement="right" popover-append-to-body="true">Click here</button>

它对我有用。

如果弹出框中有任何提交按钮或单击事件,则焦点将不起作用。所以这是有用的方法。

【讨论】:

【参考方案11】:

onclick="void(0)" 行为添加到您的一些背景元素中,点击这些元素会消除弹出框。

看看https://github.com/angular-ui/bootstrap/issues/2123

【讨论】:

【参考方案12】:

1) 使用 ng-bootstrap 进行 Popover。

2) 将 ng-bootstrap 版本更新到 3.0.0 或更高版本。 即 npm install --save @ng-bootstrap/ng-bootstrap@3.0.0

3) 更新后,您可以使用 Ngbpopover 的 [autoClose] 功能。

<button type="button" class="btn btn-outline-secondary" popoverTitle="Pop title" [autoClose]="true" ngbPopover="Click anywhere or press Escape to close (try the toggling element too)">Click to toggle</button>

4) 希望对您有所帮助!

【讨论】:

以上是关于单击外部时隐藏Angular UI Bootstrap弹出窗口的主要内容,如果未能解决你的问题,请参考以下文章

Angular 7:单击外部时关闭菜单

折叠过渡不适用于 Angular 的 UI Bootstrap

javascript 单击外部时隐藏RSForm日历

Ag-grid:在侧边栏面板外部以角度单击时隐藏列侧边栏

Laravel 8 livewire 在任务完成或在其外部单击页面时隐藏菜单组件

如何在元素外部的任何位置隐藏单击事件上的元素?