首页 文章

mouseenter上的angular-bootstrap下拉列表,并在单击之前保持下拉菜单不被隐藏 .

提问于
浏览
11

首先,我知道这些帖子:
Activating bootstrap dropdown menu on hover
Bootstrap Dropdown with Hover
How to make twitter bootstrap menu dropdown on hover rather than click
还有其他人,但还没有找到正确的解决方案,这就是我到目前为止所做的 .
首先我使用angular-bootstrap下拉指令中的is-open属性,如下所示:

<span class="dropdown" dropdown is-open="status.isopen">
  <a
    href
    class="dropdown-toggle"
    ng-mouseenter="status.isopen = true"
    ng-mouseleave="status.isopen = false"
  >
    hover me for a dropdown with angular-bootstrap
  </a>
  <ul
    class="dropdown-menu"
  >
    <li ng-repeat="choice in items">
      <a href>{{choice}}</a>
    </li>
  </ul>
</span>

似乎工作但出现了2个错误:

  • the first 是当点击下拉切换元素时,下拉菜单再次点击不再将它带回来你必须鼠标左键然后鼠标进入下拉菜单以获得下拉菜单 .

  • the second 是一个css / html问题 .

通常,下拉列表的常规css解决方案如下:

<a class="css-dropdown">
  hover here with css.
  <div class="css-dropdown-menu">
    <p>item 1</p>
    <p>item 2</p>
    <p>item 3</p>
  </div>
</a>

Notice 下拉菜单现在位于dropdown-toggle元素内,这意味着当用鼠标从下拉菜单切换到下拉菜单时,这意味着下拉菜单仍然可见,另一方面,引导下拉列表与click事件一起使用,因此不需要将下拉菜单作为下拉切换的子项,但是现在当有人想要将鼠标离开下拉切换时的行为更改为mouseenter / hover时 - 菜单消失,所以我们无法访问下拉菜单元素,这在plunker中可见

为了修复第一个错误,我刚删除了dropdown指令,然后用这样的ng-class指令替换了is-open .
改变这个:

<span class="dropdown" dropdown is-open="status.isopen">

对此:

<span class="dropdown" ng-class="{'open': status.isopen}">

其余的保持不变plunker修复了第一个bug .
第二个错误是棘手的,因为下拉菜单不再是下拉菜单的子项,当切换到菜单时,悬停效果不会持续,所以我这样做了 . 改变了这个:

<ul class="dropdown-menu">

对此:

<ul
  class="dropdown-menu"
  ng-mouseenter="status.isopen = true"
  ng-mouseleave="status.isopen = false"
>

这样做但是当点击它保持打开的下拉菜单项时出现了另一个错误,所以我继续这样做 . 改变了这个:

<li ng-repeat="choice in items">

对此:

<li ng-repeat="choice in items" ng-click="status.isopen = false">

这给了我所需的行为plunker .
也就是说,这不是一个好的解决方案,因为这里涉及很多指令以获得简单的视觉效果,我提供的最后一个plunker包含一个没有Bootstrap或AngularJS的css解决方案,尽管它是必需的行为,它不是必需的html结构或视觉结果,我需要的是在下拉切换和下拉菜单之间有一个空格而不是切换元素的填充只是一个空白空间,这使得css解决方案在这种情况下无效 .
所以,我的问题是,如果没有为悬停下拉菜单添加一个新的插件/库更干净,更容易重复使用的解决方案,有更好的方法吗?

4 回答

  • 0

    First ,在最顶层的父元素上切换(在本例中为 <span>

    <span class="btn-group" dropdown is-open="status.isopen" ng-mouseenter="status.isopen = true" ng-mouseleave="status.isopen = false">
      <a class="btn btn-primary dropdown-toggle" dropdown-toggle>
        Button dropdown <span class="caret"></span>
      </a>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </span>
    

    这将允许您想要的行为 - 同时仍允许点击显示/隐藏菜单;-)

    然而,有一个烦恼:如果你移动鼠标光标较慢并通过切换和菜单之间的小间隙,它将隐藏菜单 .

    所以 secondly ,添加一个小CSS来消除差距

    .dropdown-menu {
        margin-top: 0;
    }
    

    请参阅plunker中的操作 .

  • 0

    我知道你想要一个解决方案 without adding a new plugin/library ,但是你(或其他寻求此行为的人)可能想尝试使用No Close from Dropdown Enhancements lib来保持下拉列表打开,即使在点击其中一个选项之后:

    单击无线电添加类.noclose时不要关闭菜单 .

    <div class="btn-group">
      <button data-toggle="dropdown" class="btn btn-default dropdown-toggle">
          Checked option <span class="caret"></span>
      </button>
      <ul class="dropdown-menu noclose">
          <li>
              <input type="radio" id="gr1_1" name="gr1" value="1">
              <label for="gr1_1">Option 1</label>
          </li>
          <li>
              <input type="radio" id="gr1_2" name="gr1" value="2">
              <label for="gr1_2">Option 2</label>
          </li>
          <li>
              <input type="radio" id="gr1_3" name="gr1" value="3">
              <label for="gr1_3">Option 3</label>
          </li>
      </ul>
    </div>
    

    还为悬停问题添加CSS解决方案:

    .btn-group:hover .dropdown-menu.noclose {
        display: block;
    }
    .dropdown-menu.noclose {
        margin-top: 0px;
    }
    

    当然,不要忘记导入libs:


    在你的情况下,我建议你研究Dropdown Enhancements's source code,看它是如何工作的,也许找到一个更合适的解决方案 .

  • 0

    尝试将此行添加到您的css:

    .btn-group:hover>.dropdown-menu { display: block; margin-top: 0; }
    

    你必须删除你的is-open,ng-mouseenter和ng-mouseleave指令 .

  • 3

    以下是我提出的解决方案,同时处理同样的问题 .

    我使用了一个简单的自定义指令:

    • mouseentermouseleave 事件绑定到下拉列表,以便正确显示/隐藏菜单 .

    • 动态地将自定义CSS类添加到下拉菜单中,以防止在将光标从按钮移动到菜单时菜单消失 . Note that this solution has the advantage of not removing the visual gap between the button and menu .

    • 防止菜单在单击按钮时消失 .

    CSS规则使用 before 伪元素填充按钮和菜单之间的间隙 . 我添加了 border 属性,可以取消注释以轻松获得视觉反馈 .

    .dropdown-hover-menu::before {
      content: '';
      position: absolute;
      left: 0;
      width: 100%;
      top: -3px;
      height: 3px;
      /*border: 1px solid black;*/
    }
    

    HTML结构该片段基于dropdown section of the angular-ui bootstrap documentation中的可用示例

    angular.module('app', ['ui.bootstrap'])
      .directive('dropdownHover', function() {
        return {
          require: 'uibDropdown',
          link: function(scope, element, attrs, dropdownCtrl) {
    
            var menu = angular.element(element[0].querySelector('.dropdown-menu')),
              button = angular.element(element[0].querySelector('.dropdown-toggle'));
    
            menu.addClass('dropdown-hover-menu');
    
            element.bind('mouseenter', onMouseenter);
            element.bind('mouseleave', onMouseleave);
            button.bind('click', onClick);
    
            function openDropdown(open) {
              scope.$apply(function() {
                dropdownCtrl.toggle(open);
              });
            }
    
            function onMouseenter(event) {
              if (!element.hasClass('disabled') && !attrs.disabled) {
                openDropdown(true);
              }
            };
    
            function onMouseleave(event) {
              openDropdown(false);
            };
    
            function onClick(event) {
              event.stopPropagation();
            }
    
            scope.$on('$destroy', function() {
              element.unbind('mouseenter', onMouseenter);
              element.unbind('mouseleave', onMouseleave);
              button.unbind('click', onClick);
            });
          }
        };
      });
    
    .dropdown-hover-menu::before {
      content: '';
      position: absolute;
      left: 0;
      width: 100%;
      top: -3px;
      height: 3px;
      /*border: 1px solid black;*/
    }
    
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.3.3/ui-bootstrap-tpls.min.js"></script>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    
    <div ng-app="app">
      <div class="btn-group" uib-dropdown dropdown-hover>
        <button type="button" class="btn btn-primary dropdown-toggle">
          Button dropdown <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" uib-dropdown-menu role="menu">
          <li role="menuitem"><a href="#">Action</a>
          </li>
          <li role="menuitem"><a href="#">Another action</a>
          </li>
          <li role="menuitem"><a href="#">Something else here</a>
          </li>
          <li class="divider"></li>
          <li role="menuitem"><a href="#">Separated link</a>
          </li>
        </ul>
      </div>
    </div>
    

相关问题