Додавання ефекту слайда до випадаючого меню початкового завантаження


80

Я використовую bootstrap , і я хотів би додати анімацію до випадаючого списку. Я хочу додати до нього анімацію, ковзаючи вниз і назад, коли виходите з неї. Як я міг це зробити?

Те, що я спробував:

Зміна випадаючого файлу Js таким чином:

Як я можу зробити так, щоб випадаючий список навігації Bootstrap плавно рухався вгору і вниз?


1
Ви включили десь bootstrap-dropdown.js? я не бачу цього у заголовку .. і awwww ці тістечка. я зараз такий голодний!
ablm

Хм, всередині boostrap.js, я його включив, але він не спрацював, тому я видалив його, але повторно додав, і так, якщо видалити міні, він взагалі не спрацює
Бен Бері,

EDIT: о так, він включений.
ablm

Ммм. За замовчуванням випадаюче меню не ковзає; У зміненій версії (за посиланнями) є $ el.parent (). SlideToggle (); який викликає анімацію JQuery.
ablm

І, крім того, я зрозумів, чому ви включаєте завантажувальний файл 2 рази. bootstrap.min.js - це зменшена версія.
ablm

Відповіді:


150

Якщо ви оновитесь до Bootstrap 3 (BS3), вони виявили багато подій Javascript, які приємно пов’язати з вашою бажаною функціональністю. У BS3 цей код надасть всім вашим випадаючим меню анімаційний ефект, який ви шукаєте:

  // Add slideDown animation to Bootstrap dropdown when expanding.
  $('.dropdown').on('show.bs.dropdown', function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideDown();
  });

  // Add slideUp animation to Bootstrap dropdown when collapsing.
  $('.dropdown').on('hide.bs.dropdown', function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideUp();
  });

Ви можете прочитати про події BS3 тут, а конкретно про випадаючі тут .


4
У мене проблема з частиною slideUp цього. У режимі згортання (Chrome) ширина випадаючого списку повертається до ширини, ніби переглядається на весь екран. Під час використання FF він ковзає вниз, але ховається, а не ковзає вгору.
ScubaSteve

3
Я теж бачу цю проблему, я насправді створив інший потік, який конкретно про це запитував ... stackoverflow.com/questions/26267207/…, але я не знаю, як саме це виправити. Я відчуваю, що випадаючий клас не чекає закінчення переходу перед обробкою hidden.bs.dropdownподії.
Кайл Джонсон,

3
це працює і робить те, що я хочу, але в мобільному вікні перегляду випадаюче меню для підменю швидко зникає і виглядає непостійним - хоча дякую за частку!
Uncle Iroh

Я не можу змусити це працювати. Я постійно отримую таку помилку: "Uncaught TypeError: $ (...). Find (...). First (...). Stop не є функцією". Я не розумію, як .stop () не є функцією, якщо анімація ще якось не запущена, коли подія запускається? Чого мені не вистачає?
Джон

Дивіться відповідь Сліпоча нижче щодо мобільного виправлення.
Tashows

72

Крім того, можна уникнути використання JavaScript для випадаючого ефекту та використовувати перехід CSS3, додавши цей невеликий фрагмент коду до свого стилю:

.dropdown .dropdown-menu {
    -webkit-transition: all 0.3s;
    -moz-transition: all 0.3s;
    -ms-transition: all 0.3s;
    -o-transition: all 0.3s;
    transition: all 0.3s;

    max-height: 0;
    display: block;
    overflow: hidden;
    opacity: 0;
}

.dropdown.open .dropdown-menu { /* For Bootstrap 4, use .dropdown.show instead of .dropdown.open */
    max-height: 300px;
    opacity: 1;
}

Єдина проблема цього способу полягає в тому, що вам слід вручну вказати max-height. Якщо ви встановите дуже велике значення, ваша анімація буде дуже швидкою.

Це працює як шарм, якщо ви знаєте приблизну висоту випадаючих списків, інакше ви все одно можете використовувати javascript для встановлення точного значення максимальної висоти.

Ось невеликий приклад: DEMO


! У цьому рішенні є невелика помилка з заповненням, перевірте коментар Якова Штамма з рішенням.


2
Приємне рішення, оцініть це.
Lalit Narayan Mishra

Мені це подобається, але, на жаль, розсувна анімація працює лише один раз. Якщо я закрию меню і відкрию його знову без оновлення сторінки, воно просто відкриється миттєво. Хто-небудь ще мав цю проблему?
Nathan R

8
Чудове рішення. На жаль, є невелика помилка. Перший елемент у спадному меню все ще можна натиснути, навіть коли він згорнутий. Ви можете визначити, наводячи курсор трохи нижче згорнутого спадного меню. У цьому випадку не страшно, бо ваш перший варіант - це звичайний текст. Однак, коли це посилання, це проблема. Моє рішення полягає в тому, щоб "оживити" видимість, але затриматися після того, як інші речі закінчать анімацію. Перевірте це: jsfiddle.net/stamminator/kjLe1tfs/1
Jacob Stamm

Дякую, що вказав на цю помилку, Джейкобе. Схоже, це проблема з заповненням списку. Якщо ви не проти, я додам ваше рішення для відповіді.
MadisonTrash

1
Можна також додати pointer-events:noneдо згорнутої версії, а потім додати point-events: allдо меню, коли вона з’явиться.show
Gray Ayer

23

Я роблю щось подібне, але при наведенні курсору замість на клацання .. Це код, який я використовую, можливо, ви зможете трохи його налаштувати, щоб змусити його працювати на клік

$('.navbar .dropdown').hover(function() {
  $(this).find('.dropdown-menu').first().stop(true, true).delay(250).slideDown();
}, function() {
  $(this).find('.dropdown-menu').first().stop(true, true).delay(100).slideUp()
});

Це чудово працює! Але чи є спосіб працювати з ним при наведенні миші замість клацання?
arefin2k

Код, який я розмістив вище, наводить курсор миші, а не натискає.
Джон,

Хороший ! Дякую.
ilmk

Не працює для мене. Я додав це під <script>тегами, але нічого не сталося
YaddyVirus

16

Я не знаю, чи зможу я підняти цю тему, але я з’ясував швидке виправлення візуальної помилки, яка трапляється, коли відкритий клас видаляється занадто швидко. В основному, все, що потрібно, - це додати функцію OnComplete всередину події slideUp і скинути всі активні класи та атрибути. Виходить приблизно так:

Ось результат: Приклад завантаження

Javascript / Jquery:

$(function(){
    // ADD SLIDEDOWN ANIMATION TO DROPDOWN //
    $('.dropdown').on('show.bs.dropdown', function(e){
        $(this).find('.dropdown-menu').first().stop(true, true).slideDown();
    });

    // ADD SLIDEUP ANIMATION TO DROPDOWN //
    $('.dropdown').on('hide.bs.dropdown', function(e){
        e.preventDefault();
        $(this).find('.dropdown-menu').first().stop(true, true).slideUp(400, function(){
            //On Complete, we reset all active dropdown classes and attributes
            //This fixes the visual bug associated with the open class being removed too fast
            $('.dropdown').removeClass('show');
            $('.dropdown-menu').removeClass('show');
            $('.dropdown').find('.dropdown-toggle').attr('aria-expanded','false');
        });
    });
});

У демонстраційному меню відкривається одне меню після натискання декількох поспіль.
SventoryMang

@DOTang так, я думаю, це не було ідеально, отже, швидке виправлення, я думаю, невеликий рефакторинг зробив би це краще. Сподіваємось, до моменту виходу Bootstrap4 вони це виправлять
IndieRok

11

ось моє рішення для слайд-ефекту:

   // Add slideup & fadein animation to dropdown
   $('.dropdown').on('show.bs.dropdown', function(e){
      var $dropdown = $(this).find('.dropdown-menu');
      var orig_margin_top = parseInt($dropdown.css('margin-top'));
      $dropdown.css({'margin-top': (orig_margin_top + 10) + 'px', opacity: 0}).animate({'margin-top': orig_margin_top + 'px', opacity: 1}, 300, function(){
         $(this).css({'margin-top':''});
      });
   });
   // Add slidedown & fadeout animation to dropdown
   $('.dropdown').on('hide.bs.dropdown', function(e){
      var $dropdown = $(this).find('.dropdown-menu');
      var orig_margin_top = parseInt($dropdown.css('margin-top'));
      $dropdown.css({'margin-top': orig_margin_top + 'px', opacity: 1, display: 'block'}).animate({'margin-top': (orig_margin_top + 10) + 'px', opacity: 0}, 300, function(){
         $(this).css({'margin-top':'', display:''});
      });
   });

Дякую. Ваш код працює ідеально. Однак я не зовсім розумію, чому нам потрібно мати $(this).css({'margin-top':''});@Vedmant
DucCuong

Це для того, щоб видалити параметр margin-top після завершення анімації, на випадок, якщо в випадаючих списках додаються поля в спеціальних стилях (як у моїй темі). Він повинен працювати без нього, оскільки він анімує до orig_margin_top назад, але чистіше не залишати зайвих вбудовані стилі після завершення анімації.
Ведмант

9

Оновлення Bootstrap 2018

У Boostrap 4 .openклас замінено на .show. Я хотів реалізувати це, використовуючи лише транзити CSS без потреби в додаткових JS або jQuery ...

.show > .dropdown-menu {
  max-height: 900px;
  visibility: visible;
}

.dropdown-menu {
  display: block;
  max-height: 0;
  visibility: hidden;
  transition: all 0.5s ease-in-out;
  overflow: hidden;
}

Демо: https://www.codeply.com/go/3i8LzYVfMF

Примітка: max-heightможна встановити будь-яке велике значення, якого достатньо для розміщення випадаючого вмісту.


Це працює чудово. Для мене мені навіть не потрібно було вказувати максимальну висоту, оскільки я намагався досягти іншого ефекту за допомогою margin-top.
Верховний Дельфін

мені це подобається, вам потрібен лише css без купу js-кодів ..
aswzen

8

Після натискання це можна зробити, використовуючи код нижче

$('.dropdown-toggle').click(function() {
  $(this).next('.dropdown-menu').slideToggle(500);
});

Це працює добре, але коли ви втрачаєте фокус, випадаюче меню залишається відкритим, що не є нормальним.
Barry Michael Doyle

7

Я використовую код вище, але змінив ефект затримки за допомогою slideToggle.

Він слайди випадаючого меню при наведенні з анімацією.

$('.navbar .dropdown').hover(function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideToggle(400);
    }, function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideToggle(400)
    });

1
насправді не потрібно визначати це двічі. при використанні тумблера він буде працювати без другого.
Даллас,

3

Розширена відповідь - це була моя перша відповідь, тому вибачте, якщо раніше не було достатньо деталей.

Для Bootstrap 3.x я особисто віддаю перевагу анімації CSS, і я використовую animate.css та разом із випадаючими хуками Bootstrap Javascript. Хоча це може мати не той ефект, який ви шукаєте, це досить гнучкий підхід.

Крок 1: Додайте animate.css на свою сторінку за допомогою тегів head:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.4.0/animate.min.css">

Крок 2: Використовуйте стандартний Bootstrap HTML на тригері:

<div class="dropdown">
  <button type="button" data-toggle="dropdown">Dropdown trigger</button>

  <ul class="dropdown-menu">
    ...
  </ul>
</div>

Крок 3: Потім додайте 2 атрибути власних даних до елемента меню, що випадає; випадаючі дані для вхідної анімації та випадаючі дані для вихідної анімації. Це можуть бути будь-які ефекти animate.css, такі як fadeIn або fadeOut

<ul class="dropdown-menu" data-dropdown-in="fadeIn" data-dropdown-out="fadeOut">
......
</ul>

Крок 4: Далі додайте такий Javascript, щоб прочитати атрибути даних, що випадають / випадають, і реагувати на зачепи / події API Bootstrap Javascript ( http://getbootstrap.com/javascript/#dropdowns-events ):

var dropdownSelectors = $('.dropdown, .dropup');

// Custom function to read dropdown data
// =========================
function dropdownEffectData(target) {
  // @todo - page level global?
  var effectInDefault = null,
      effectOutDefault = null;
  var dropdown = $(target),
      dropdownMenu = $('.dropdown-menu', target);
  var parentUl = dropdown.parents('ul.nav'); 

  // If parent is ul.nav allow global effect settings
  if (parentUl.size() > 0) {
    effectInDefault = parentUl.data('dropdown-in') || null;
    effectOutDefault = parentUl.data('dropdown-out') || null;
  }

  return {
    target:       target,
    dropdown:     dropdown,
    dropdownMenu: dropdownMenu,
    effectIn:     dropdownMenu.data('dropdown-in') || effectInDefault,
    effectOut:    dropdownMenu.data('dropdown-out') || effectOutDefault,  
  };
}

// Custom function to start effect (in or out)
// =========================
function dropdownEffectStart(data, effectToStart) {
  if (effectToStart) {
    data.dropdown.addClass('dropdown-animating');
    data.dropdownMenu.addClass('animated');
    data.dropdownMenu.addClass(effectToStart);    
  }
}

// Custom function to read when animation is over
// =========================
function dropdownEffectEnd(data, callbackFunc) {
  var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
  data.dropdown.one(animationEnd, function() {
    data.dropdown.removeClass('dropdown-animating');
    data.dropdownMenu.removeClass('animated');
    data.dropdownMenu.removeClass(data.effectIn);
    data.dropdownMenu.removeClass(data.effectOut);

    // Custom callback option, used to remove open class in out effect
    if(typeof callbackFunc == 'function'){
      callbackFunc();
    }
  });
}

// Bootstrap API hooks
// =========================
dropdownSelectors.on({
  "show.bs.dropdown": function () {
    // On show, start in effect
    var dropdown = dropdownEffectData(this);
    dropdownEffectStart(dropdown, dropdown.effectIn);
  },
  "shown.bs.dropdown": function () {
    // On shown, remove in effect once complete
    var dropdown = dropdownEffectData(this);
    if (dropdown.effectIn && dropdown.effectOut) {
      dropdownEffectEnd(dropdown, function() {}); 
    }
  },  
  "hide.bs.dropdown":  function(e) {
    // On hide, start out effect
    var dropdown = dropdownEffectData(this);
    if (dropdown.effectOut) {
      e.preventDefault();   
      dropdownEffectStart(dropdown, dropdown.effectOut);   
      dropdownEffectEnd(dropdown, function() {
        dropdown.dropdown.removeClass('open');
      }); 
    }    
  }, 
});

Крок 5 (необов’язково): Якщо ви хочете прискорити або змінити анімацію, ви можете зробити це за допомогою CSS, як показано нижче:

.dropdown-menu.animated {
  /* Speed up animations */
  -webkit-animation-duration: 0.55s;
  animation-duration: 0.55s;
  -webkit-animation-timing-function: ease;
  animation-timing-function: ease;
}

Написав статтю з більш детальною інформацією та завантаження, якщо хтось зацікавив: article: http://bootbites.com/tutorials/bootstrap-dropdown-effects-animatecss

Сподіваюся, це корисно, і це друге написання має рівень деталізації, який потрібен Тому


3
Було б добре хоча б включити у свою відповідь деякі деталі - просто посилання на ваш сайт насправді не є гарною відповіддю.
ajshort

@GeraldSchneider оновив відповідь детальніше. Це була моя перша відповідь на stackoverflow, тому вдячні за відгуки.
Том Джеймс

2
$('.navbar .dropdown').hover(function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideDown();
}, function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideUp();
});

Цей код працює, якщо ви хочете показати випадаючі меню при наведенні.

Я тільки змінив .slideToggleдо .slideDown& .slideUp, і видалив (400)час


1

Ось гарне просте рішення з використанням jQuery яке добре працює:

$('.dropdown-toggle').click(function () {
    $(this).next('.dropdown-menu').slideToggle(300);
});

$('.dropdown-toggle').focusout(function () {
    $(this).next('.dropdown-menu').slideUp(300);
})

Перемикання анімації слайдів відбувається при натисканні, і воно завжди ковзає назад, втрачаючи фокус.

Змінити 300 значення на що завгодно, чим менше число, тим швидша анімація.

Редагувати:

Це рішення буде працювати лише для робочих столів. Для гарного відображення для мобільних пристроїв потрібні додаткові модифікації.


Це справді працює для мене, але після того, як я переміщую мишу до підменю (тобто подалі від dropdown-toggle), воно знову зникає, це означає, що я не можу вибрати пункти підменю
Бассі,

1

ПОЗНАЧЕННЯ 3

Додано, тому що я постійно потрапляю в розв’язок у цій темі, і це мене штовхає кожного разу.

В основному випадаючий список BS негайно видаляє .openклас з батьківського, тому ковзання вгору не працює.

Використовуйте той самий біт, що й інші рішення для slideDown ();

// ADD SLIDEUP ANIMATION TO DROPDOWN //
$('.dropdown').on('hide.bs.dropdown', function(e){
  e.preventDefault();
  $(this).find('.dropdown-menu').first().stop(true, true).slideUp(300, function(){
    $(this).parent().removeClass('open');
  });
});

1

Вступ

На момент написання статті оригінальній відповіді зараз 8 років. Проте я відчуваю, що ще не було належного рішення вихідного питання.

Bootstrap з того часу пройшов довгий шлях і зараз знаходиться на рівні 4.5.2 . Ця відповідь стосується саме цієї версії.

Проблема з усіма іншими рішеннями поки що

Проблема з усіма іншими відповідями полягає в тому, що, хоча вони підключаються до show.bs.dropdown/ hide.bs.dropdown, подальші події shown.bs.dropdown/ hidden.bs.dropdownабо запускаються занадто рано (анімація все ще триває), або вони взагалі не запускаються, оскільки їх було придушено (e.preventDefault() ).

Чистий розчин

Оскільки реалізація show()та hide()в Dropdownкласі Bootstraps мають деякі подібності, я згрупував їх разом, toggleDropdownWithAnimation()імітуючи початкову поведінку, і додав маленькі допоміжні функції QoL до showDropdownWithAnimation()та hideDropdownWithAnimation().
toggleDropdownWithAnimation()створює подію shown.bs.dropdown/ hidden.bs.dropdownподію так само, як це робить Bootstrap. Потім ця подія запускається після завершення анімації - як і слід було очікувати.

/**
 * Toggle visibility of a dropdown with slideDown / slideUp animation.
 * @param {JQuery} $containerElement The outer dropdown container. This is the element with the .dropdown class.
 * @param {boolean} show Show (true) or hide (false) the dropdown menu.
 * @param {number} duration Duration of the animation in milliseconds
 */
function toggleDropdownWithAnimation($containerElement, show, duration = 300): void {
    // get the element that triggered the initial event
    const $toggleElement = $containerElement.find('.dropdown-toggle');
    // get the associated menu
    const $dropdownMenu = $containerElement.find('.dropdown-menu');
    // build jquery event for when the element has been completely shown
    const eventArgs = {relatedTarget: $toggleElement};
    const eventType = show ? 'shown' : 'hidden';
    const eventName = `${eventType}.bs.dropdown`;
    const jQueryEvent = $.Event(eventName, eventArgs);

    if (show) {
        // mimic bootstraps element manipulation
        $containerElement.addClass('show');
        $dropdownMenu.addClass('show');
        $toggleElement.attr('aria-expanded', 'true');
        // put focus on initial trigger element
        $toggleElement.trigger('focus');
        // start intended animation
        $dropdownMenu
            .stop() // stop any ongoing animation
            .hide() // hide element to fix initial state of element for slide down animation
            .slideDown(duration, () => {
            // fire 'shown' event
            $($toggleElement).trigger(jQueryEvent);
        });
    }
    else {
        // mimic bootstraps element manipulation
        $containerElement.removeClass('show');
        $dropdownMenu.removeClass('show');
        $toggleElement.attr('aria-expanded', 'false');
        // start intended animation
        $dropdownMenu
            .stop() // stop any ongoing animation
            .show() // show element to fix initial state of element for slide up animation
            .slideUp(duration, () => {

            // fire 'hidden' event
            $($toggleElement).trigger(jQueryEvent);
        });
    }
}

/**
 * Show a dropdown with slideDown animation.
 * @param {JQuery} $containerElement The outer dropdown container. This is the element with the .dropdown class.
 * @param {number} duration Duration of the animation in milliseconds
 */
function showDropdownWithAnimation($containerElement, duration = 300) {
    toggleDropdownWithAnimation($containerElement, true, duration);
}

/**
 * Hide a dropdown with a slideUp animation.
 * @param {JQuery} $containerElement The outer dropdown container. This is the element with the .dropdown class.
 * @param {number} duration Duration of the animation in milliseconds
 */
function hideDropdownWithAnimation($containerElement, duration = 300) {
    toggleDropdownWithAnimation($containerElement, false, duration);
}

Приєднати слухачів подій

Тепер, коли ми написали відповідні зворотні дзвінки для показу / приховування випадаючого меню з анімацією, давайте насправді прив’яжемо їх до правильних подій.

Типовою помилкою, яку я багато бачив в інших відповідях, є безпосереднє прив’язування слухачів подій до елементів. Хоча це добре працює для елементів DOM, наявних на момент реєстрації прослуховувача подій, воно не прив'язується до елементів, доданих пізніше.

Ось чому вам, як правило, краще прив'язувати безпосередньо до document:

$(function () {

    /* Hook into the show event of a bootstrap dropdown */
    $(document).on('show.bs.dropdown', '.dropdown', function (e) {
        // prevent bootstrap from executing their event listener
        e.preventDefault();
        
        showDropdownWithAnimation($(this));
    });

    /* Hook into the hide event of a bootstrap dropdown */
    $(document).on('hide.bs.dropdown', '.dropdown', function (e) {
        // prevent bootstrap from executing their event listener
        e.preventDefault();
          
        hideDropdownWithAnimation($(this));
    });

});

0

Для Bootstrap 3 ця зміна наведених вище відповідей робить мобільну slideUp()анімацію більш плавною; відповіді вище містять нестабільну анімацію, оскільки Bootstrap .openнегайно видаляє клас з батьківського елемента перемикача, тому цей код відновлює клас, доки slideUp()анімація не закінчиться.

// Add animations to topnav dropdowns
// based on https://stackoverflow.com/a/19339162
// and https://stackoverflow.com/a/52231970

$('.dropdown')
  .on('show.bs.dropdown', function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideDown(300);
  })
  .on('hide.bs.dropdown', function() {
    $(this).find('.dropdown-menu').first().stop(true, false).slideUp(300, function() {
      $(this).parent().removeClass('open');
    });
  })
  .on('hidden.bs.dropdown', function() {
    $(this).addClass('open');
  });

Основні відмінності:

  • У hide.bs.dropdownобробнику подій я використовую .stop()значення за замовчуванням ( false) для другого аргументу (jumpToEnd )
  • hidden.bs.dropdownОброблювач подій відновлює .openклас для батьківського DropDown перемикання, і він робить це в значній мірі відразу ж після того , як клас був першим був знищений. Тим часом slideUp()анімація все ще працює, і, як і у відповідях вище, її зворотний виклик "the-animation-is-completed" відповідає за остаточне видалення .openкласу від батьківського.
  • Методи поєднані в ланцюжки, оскільки селектор для кожного обробника подій однаковий
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.