[英]How to Animate closing dropdown menu with js and css?
我有一个带有子菜单项的菜单,我在打开下拉菜单时设法用 css 关键帧创建了一个简单的动画,但是当下拉菜单关闭时我不能做同样的事情。 关闭下拉菜单时如何添加动画? 如您所见,当您关闭下拉菜单时,没有过渡,它会立即消失。
旧片段
var dropdownBtn = document.querySelectorAll('.menu-btn'); //Add this for toggling dropdown lastOpened = null; dropdownBtn.forEach(btn => btn.addEventListener('click', function() { var menuContent = this.nextElementSibling; menuContent.classList.toggle("show"); //Add this for toggling dropdown if (lastOpened && lastOpened !== menuContent) lastOpened.classList.remove("show"); lastOpened = menuContent; }));
.menu-btn { background: #e0e0e0; padding: 10px; margin: 5px 0px 0px 0px; } .menu-btn:hover { background: #000; color: #fff; } .drop_container { display: none; background-color: #017575; animation:animateFromBottom .3s; } .drop_container.show { display: block; } .drop_container > .item { display: flex; flex-direction: column; margin-left: 10px; padding: 10px 0px 0px 0px; } @keyframes animateFromBottom { from{bottom:-50px;opacity:0} to{bottom:0;opacity:1} } @keyframes animateToBottom { from{bottom:0;opacity:1} to{bottom:-50px;opacity:0} }
<div class="dropdown-menu"> <div class="menu-btn">One</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> <div class="menu-btn">Two</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> </div>
编辑片段:我决定不使用 css 关键帧,只使用最大高度进行过渡。 这让我更容易做出改变,我仍然只是一个初学者,只是坚持简单的东西。 但是,当您在项目之间切换时,它仍然没有播放任何动画。 我看到@EmielZuurbier 的解决方案即使在从一个项目切换到另一个项目时也会添加动画,我怎样才能将它添加到我修改后的代码中?
var dropdownBtn = document.querySelectorAll('.menu-btn'); //Add this for toggling dropdown lastOpened = null; dropdownBtn.forEach(btn => btn.addEventListener('click', function() { var menuContent = this.nextElementSibling; if (!menuContent.classList.contains("show")) { menuContent.classList.add("show"); menuContent.classList.remove("hide"); } else { menuContent.classList.add("hide"); menuContent.classList.remove("show"); } //Add this for toggling dropdown if (lastOpened && lastOpened !== menuContent) lastOpened.classList.remove("show"); lastOpened = menuContent; }));
.menu-btn { background: #e0e0e0; padding: 10px; margin: 5px 0px 0px 0px; } .menu-btn:hover { background: #000; color: #fff; } .drop_container { overflow: hidden; max-height: 0; } .drop_container.show { max-height: 300px; transition: max-height 0.3s ease-in; } .drop_container.hide { overflow: hidden; max-height: 0; transition: max-height 0.3s ease-out; } .drop_container > .item { display: flex; flex-direction: column; margin-left: 10px; padding: 10px 0px 0px 0px; }
<div class="dropdown-menu"> <div class="menu-btn">One</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> <div class="menu-btn">Two</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> </div>
有多种方法可以实现这一目标。 因为您使用display
属性显示和隐藏下拉列表,所以我们需要坚持使用动画。
为animateToBottom
关键帧创建一个新类。 这个类应该添加在一个带有show
类的元素应该动画出来之后。
只有在“out”动画完成后才能删除show
类。 通过animationend
事件,我们可以看到动画何时结束,这样我们就可以隐藏下拉菜单。
const dropdownBtns = document.querySelectorAll('.menu-btn'); let lastOpened = null; dropdownBtns.forEach(btn => btn.addEventListener('click', function() { const menuContent = this.nextElementSibling; if (lastOpened !== null) { const target = lastOpened; target.addEventListener('animationend', () => { target.classList.remove('show', 'animate-out'); if (target === lastOpened) { lastOpened = null; } }, { once: true }); target.classList.add('animate-out'); } if (lastOpened !== menuContent) { menuContent.classList.add('show'); lastOpened = menuContent; } }));
.menu-btn { background: #e0e0e0; padding: 10px; margin: 5px 0px 0px 0px; } .menu-btn:hover { background: #000; color: #fff; } .drop_container { display: none; background-color: #017575; animation: animateFromBottom .3s; } .drop_container.show { display: block; } .drop_container.show.animate-out { animation: animateToBottom .3s; } .drop_container>.item { display: flex; flex-direction: column; margin-left: 10px; padding: 10px 0px 0px 0px; } @keyframes animateFromBottom { from { transform: translate3d(0, 10px, 0); opacity: 0 } to { transform: translate3d(0, 0, 0); opacity: 1 } } @keyframes animateToBottom { from { transform: translate3d(0, 0, 0); opacity: 1 } to { transform: translate3d(0, 10px, 0); opacity: 0 } }
<div class="dropdown-menu"> <div class="menu-btn">One</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> <div class="menu-btn">Two</div> <div class="drop_container"> <a class="item" href="#">Contact Us</a> <a class="item" href="#">Visit Us</a> </div> </div>
这是一个涉及CSS 过渡和CSS 自定义属性的不同解决方案。
使用这种方法,手风琴菜单部分最初设置为.hide
。
然后在.hide
和.show
之间切换这些部分(使用.classList.toggle()
)。
.hide
表示height
为0
.show
类表示height
为var(--openHeight)
height
将在这两个值之间进行动画处理。
var(--openHeight)
是为每个menuItemData
单独计算的 - 它等效于menuItemData.scrollHeight
。
通过这种技术,我们可以在0
和 CSS 无法猜测的值之间实现平滑的 CSS 过渡,但 JavaScript 可以很容易地告诉我们。
工作示例:
let dropdownMenuItemTitles = document.querySelectorAll('.dropdown-menu-item-title'); dropdownMenuItemTitles.forEach(menuItemTitle => { menuItemTitle.addEventListener('click', (e) => { const menuItemData = e.target.nextElementSibling; menuItemData.style.setProperty('--openHeight', menuItemData.scrollHeight + 'px'); menuItemData.classList.toggle('show'); menuItemData.classList.toggle('hide'); }) });
.dropdown-menu-item-title { background-color: #a0a0a0; padding: 10px; margin: 5px 0px 0px 0px; cursor: pointer; } .dropdown-menu-item-title:hover { background: #000; color: #fff; } .dropdown-menu-item-data { margin: 0; overflow: hidden; transition: height 0.3s ease-out; } .dropdown-menu-item-data.hide { height: 0; } .dropdown-menu-item-data.show { height: var(--openHeight); } .dropdown-submenu { padding: 0; background-color: #e0e0e0; list-style-type: none; } .dropdown-submenu-item { padding: 12px; }
<dl class="dropdown-menu"> <div> <dt class="dropdown-menu-item-title">One</dt> <dd class="dropdown-menu-item-data hide"> <ul class="dropdown-submenu"> <li class="dropdown-submenu-item"><a href="#">Contact Us</a></li> <li class="dropdown-submenu-item"><a href="#">Visit Us</a></li> </ul> </dd> </div> <div> <dt class="dropdown-menu-item-title">Two</dt> <dd class="dropdown-menu-item-data hide"> <ul class="dropdown-submenu"> <li class="dropdown-submenu-item"><a href="#">About Us</a></li> <li class="dropdown-submenu-item"><a href="#">Visit Us</a></li> <li class="dropdown-submenu-item"><a href="#">Opening Times</a></li> <li class="dropdown-submenu-item"><a href="#">Contact Us</a></li> </ul> </dd> </div> <div> <dt class="dropdown-menu-item-title">Three</dt> <dd class="dropdown-menu-item-data hide"> <ul class="dropdown-submenu"> <li class="dropdown-submenu-item"><a href="#">About Us</a></li> <li class="dropdown-submenu-item"><a href="#">Visit Us</a></li> <li class="dropdown-submenu-item"><a href="#">Contact Us</a></li> </ul> </dd> </div> </dl> </div>
延伸阅读:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.