向引导下拉菜单添加幻灯片效果


80

我正在使用bootstrap,我想在下拉菜单中添加动画。我想向其中添加动画,滑出时将其上下滑动。我该怎么办?

我尝试过的事情:

像这样更改Js下拉文件:

如何使Bootstrap的导航下拉列表平滑地上下滑动?


1
您是否在某个地方包含了bootstrap-dropdown.js?我没有在标题中看到它..和这些蛋糕。我现在好饿!
2012年

嗯,它在boostrap.js里面,我确实包含了它,但是没有起作用,所以我删除了它,但是我重新添加了它,是的,如果我删除了迷你模型,它根本无法工作
Ben Beri 2012年

编辑:哦,是的,它已包括在内。
2012年

嗯 默认下拉列表不会滑动;在修改后的版本(来自链接)上,有一个$ el.parent()。slideToggle();。调用JQuery动画。
2012年

顺便说一句,我不明白你为什么要包括bootstrap 2次。bootstrap.min.js是缩小版。
2012年

Answers:


149

如果您更新到Bootstrap 3(BS3),它们会暴露很多Java事件,可以很好地将所需的功能绑定到其中。在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 / ...但我不知道确切如何解决它。我觉得Dropdown类在处理hidden.bs.dropdown事件之前没有等待转换完成。
凯尔·约翰逊

3
这可以满足我的需求,但是在移动视口中,子菜单的下拉幻灯片消失得很快,看起来很不连贯-尽管感谢分享!
Iroh叔叔

我无法使它正常工作。我不断收到以下错误:“未捕获的TypeError:$(...)。find(...)。first(...)。stop不是函数”。我不明白.stop()是不是一个函数,除非触发事件时动画以某种方式还没有开始?我想念什么?
约翰(John John)

有关移动修复的更多信息,请参见Slipoch的答案。
Tashows 18/09/18

71

通过向您的样式添加以下这段代码,也可以避免使用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


!在此解决方案中存在一个带有填充的小错误,请在解决方案中检查Jacob Stamm的评论。


2
不错的解决方案,不胜感激。
Lalit Narayan Mishra '02

我喜欢这个,但不幸的是,向下滑动动画只能播放一次。如果我关闭菜单并再次打开它而不刷新页面,则它会立即打开。还有其他人有这个问题吗?
内森·R

8
很好的解决方案。不幸的是,有一个小错误。即使下拉菜单中的第一项仍然可以单击。您可以将鼠标悬停在折叠下拉菜单的下方,以此来判断。在这种情况下,没什么大不了的,因为您的首选是纯文本。但是,当它是链接时,这是一个问题。我的解决方案是同时对可见性进行“动画处理”,但是要在其他内容完成动画处理后再进行延迟。看看:jsfiddle.net/stamminator/kjLe1tfs/1
Jacob Stamm

感谢您指出该错误,Jacob。看起来这是列表中填充的问题。如果您不介意,我会添加您的解决方案来回答。
MadisonTrash

1
也可以将其添加pointer-events:none到折叠后的版本中,然后将其添加point-events: all到菜单中.show
Gray Ayer

24

我正在执行类似的操作,但是将鼠标悬停而不是单击。.这是我正在使用的代码,您可能可以对其进行一些调整以使其在单击时起作用

$('.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

我上面发布的代码位于鼠标悬停而不是单击上。
Yohn

好一个!谢谢。
ilmk

不为我工作。我在<script>标签下添加了此标签,但未发生任何事情
YaddyVirus

16

我不知道我是否可以碰到这个线程,但是我想出了一个快速修复开放类被快速移除时发生的视觉错误的方法。基本上,要做的就是在slideUp事件内添加OnComplete函数并重置所有活动的类和属性。像这样:

结果如下:Bootply示例

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是的,我想它并不完美,因此快速修复,我想稍微重构一下就能使它更好。希望
等到

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 2015年

这是为了在动画完成后删除margin-top参数,以防自定义样式(如我的主题)中的下拉菜单中添加了一些边距。动画完成后的内联样式。
Vedmant'3

9

更新2018年Bootstrap 4

在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
至尊海豚

我喜欢这个,U只需要CSS没有一堆JS代码..
aswzen

8

点击时,可以使用以下代码完成

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

这很好用,但是当您失去焦点时,下拉列表仍保持打开状态,这是不正常的。
巴里·迈克尔·道尔

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 Dropdown Javascript Hooks。尽管它可能并不完全具有您想要的效果,但是它是一种非常灵活的方法。

第1步:使用head标签将animate.css添加到您的页面:

<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:然后向dropdrop-menu元素添加2个自定义数据属性;输入动画的数据下拉输入和输出动画的数据下拉输出。这些可以是任何animate.css效果,例如fadeIn或fadeOut

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

步骤4:接下来,添加以下Javascript以读取data-dropdown-in / out数据属性,并对Bootstrap Javascript API钩子/事件(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;
}

如果有兴趣的话,写一篇更详细的文章并下载:文章: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),它再次消失,这意味着我无法选择子菜单项
Bassie

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');
  });
});

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类的下拉菜单切换的母公司,它几乎立即后级已经先取出做到这一点。同时,slideUp()动画仍在运行,就像上面的答案一样,其“动画完成”回调负责最终删除动画。.open从其父级类。
  • 方法被链接在一起,因为每个事件处理程序的选择器相同

0

介绍

截至撰写本文时,原始答案现在已经8岁了。我仍然觉得原始问题还没有适当的解决方案。

那时以来,Bootstrap已经走了很长一段路,现在是4.5.2。这个答案解决了这个版本。

迄今为止所有其他解决方案的问题

所有其他答案的问题是,当它们挂接到show.bs.dropdown/时hide.bs.dropdown,后续事件shown.bs.dropdown/hidden.bs.dropdown要么触发得太早(动画仍在进行中),要么由于被抑制(e.preventDefault())而根本不触发。

干净的解决方案

由于实施show()hide()在引导程序Dropdown类有一些相似之处,我在组合在一起,他们toggleDropdownWithAnimation()mimicing原来的行为,并加入少许的生活质量辅助函数时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));
    });

});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.