Подтвердить что ты не робот

Angular-bootstrap раскрывающийся на мышином центре и удерживайте раскрывающееся меню от скрытия до нажатия.

Во-первых, я знаю об этих сообщениях:
Активация выпадающего меню начальной загрузки при наведении курсора
Bootstrap выпадающий с Hover
Как сделать так, чтобы всплывающее меню Twitter запускалось при наведении курсора, а не при нажатии
И другие, но пока не нашли правильного решения, вот что я сделал до сих пор.
Сначала я использовал атрибут is-open из раскрывающейся директивы angular-bootstrap следующим образом:

<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 ошибки:

  • первый - при нажатии на элемент dropdown-toggle раскрывающееся меню исчезает, повторное нажатие не приводит к возврату, вам нужно отпустить кнопку мыши, а затем мышью ввести выпадающее меню, чтобы вернуть раскрывающееся меню.
  • вторая - это проблема 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>

Обратите внимание, теперь раскрывающееся меню находится внутри элемента dropdown-toggle, что означает, что при перемещении с помощью мыши из раскрывающегося меню в раскрывающееся меню оно перемещается от родителя к потомку, поэтому в основном мы все еще находимся над dropdown-toggle, так как мы находимся в его потомке, что означает, что выпадающее меню будет по-прежнему видимым, с другой стороны, выпадающий список начальной загрузки работает с событием click, поэтому наличие раскрывающегося меню в качестве дочернего элемента выпадающего переключателя не требуется, но теперь, когда кто-то хочет изменить поведение на mouseenter/hover, как только мышь покидает выпадающий список, выпадающее меню исчезает, поэтому у нас больше нет доступа к элементам выпадающего меню, это видно в этом элементе

Чтобы исправить первую ошибку, я просто удалил выпадающую директиву, а затем заменил is-open на директиву ng-class следующим образом.
Изменить это:

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

на это:

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

Остальные остаются теми же плунжерами, которые исправили первую ошибку.
Вторая ошибка хитрая, так как выпадающее меню больше не является дочерним по отношению к выпадающему списку - эффект наведения не будет длиться последним при переходе от переключателя к меню, поэтому я сделал это. Изменено это:

<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">

Это дает мне необходимое поведение поршень.
Тем не менее, это не очень хорошее решение, так как здесь много директив для простого визуального эффекта, последний предоставленный мною плункер содержит решение css без Bootstrap или AngularJS, хотя это требуемое поведение, которое не требуется html структура или визуальный результат, мне нужно, чтобы между выпадающим-переключателем и выпадающим меню был пробел, а не отступ элемента-переключателя, а просто пустое пространство, что делает решение css недопустимым в этой ситуации.
Итак, мой вопрос, есть ли лучший способ сделать это, не добавляя новый плагин/библиотеку, более чистое и легко повторно используемое решение для всплывающего меню при наведении?

4b9b3361

Ответ 1

Во-первых,, переключите самый верхний родительский элемент (в данном случае, <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>

Это позволит вам поведение, которое вы хотели - при этом все еще позволяя щелкнуть, чтобы показать/скрыть меню ;-)

Однако есть раздражение: если вы перемещаете курсор мыши медленнее и пропускаете небольшой промежуток между переключателем и меню, оно скрывает меню.

Итак, во-вторых,, добавьте небольшой CSS, чтобы убрать пробел

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

Смотрите действие в этом плунжере.

Ответ 2

Я знаю, что вам нужно решение without adding a new plugin/library, но вы (или другие люди, ищущие такого поведения), возможно, захотите попробовать Нет закрытия из расширений Dropdown 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;
}

И, конечно же, не забудьте импортировать библиотеки:


В вашем случае я предлагаю вам изучить исходный код Dropdown Enhancements, чтобы узнать, как он работает, и, возможно, найти более подходящее решение.

Ответ 3

Попробуйте добавить эту строку в свой CSS:

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

Вам придется удалить директивы is-open, ng-mouseenter и ng-mouseleave.

Ответ 4

Ниже приведено решение, которое я придумала, работая над той же проблемой.

Я использовал простую пользовательскую директиву, которая:

  • привязывает события mouseenter и mouseleave к раскрывающемуся списку, чтобы правильно отобразить/скрыть меню.
  • динамически добавляет пользовательский класс CSS в раскрывающееся меню, чтобы предотвратить исчезновение меню при перемещении курсора от кнопки к меню. Обратите внимание, что это решение имеет то преимущество, что не устраняет визуальный разрыв между кнопкой и меню.
  • предотвращает исчезновение меню при нажатии кнопки.

Правило CSS использует псевдоэлемент before, чтобы заполнить пробел между кнопкой и меню. Я добавил свойство border, которое можно раскомментировать, чтобы легко получить визуальную обратную связь.

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

HTML-структура фрагмента основана на доступных примерах в раскрывающемся разделе документации по загрузке angular-ui

.

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="#" onclick="location.href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'; return false;" 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>