You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

技术求助:如何实现滑动菜单的滑入滑出双向动画效果?

嘿,我瞅了下你的代码,问题出在这几个地方:

  1. 你直接用display: none来隐藏菜单,这会让浏览器立刻把元素从布局中移除,动画根本来不及执行就没了;
  2. JS里hideMenu函数的判断写了if(navMenu.style.display = "block"),这是赋值操作不是判断,应该用==或者更靠谱的类名判断;
  3. 还有个小bug:#container里的display: absolute是错的,应该是position: absolute,不然布局会乱。

下面给你两种修复方案,推荐第一种用transition的,更简洁好维护:

方案一:用CSS Transition实现平滑切换(推荐)

这种方式通过控制元素的transform属性来实现滑入滑出,不用操心动画结束后的状态,代码更清爽。

修改后的CSS

#main-container {
  width: 350px;
  height: 600px;
  border: 1px solid black;
  position: absolute;
  overflow: hidden;
}

#container {
  width: 350px;
  height: 100%;
  position: absolute; /* 修复display:absolute的错误 */
  z-index: 1;
  background: rgba(0, 102, 199, 0.8);
}

#navBtn {
  width: 50px;
  height: 50px;
  background: red;
  position: absolute;
  z-index: 999;
}

#navMenu {
  width: 250px;
  height: 100%;
  background: blue;
  position: absolute;
  z-index: 9999;
  top: 0;
  transform: translateX(-250px); /* 初始完全隐藏在左侧 */
  transition: transform 0.5s ease; /* 0.5秒平滑过渡 */
}

#navMenu.open {
  transform: translateX(0); /* 滑入到可视区域 */
}

#navMenu.close {
  transform: translateX(-250px); /* 滑出到隐藏区域 */
}

修改后的JS

var navBtn = document.getElementById("navBtn");
var navMenu = document.getElementById("navMenu");
var container = document.getElementById("container");

// 初始状态移除所有控制类
navMenu.classList.remove('open', 'close');

navBtn.addEventListener("click", toggleMenu);
container.addEventListener("click", hideMenu);

function toggleMenu(e) {
  e.stopPropagation(); // 阻止点击按钮时事件冒泡到container,避免刚打开就关闭
  if (navMenu.classList.contains('open')) {
    hideMenu();
  } else {
    showMenu();
  }
}

function showMenu() {
  navMenu.classList.add('open');
  navMenu.classList.remove('close');
  container.style.background = "rgba(0, 102, 199, 1)";
}

function hideMenu() {
  navMenu.classList.add('close');
  navMenu.classList.remove('open');
  container.style.background = "lightblue";
  // 如果需要动画结束后彻底隐藏(可选,其实transform已经看不见了)
  // navMenu.addEventListener('transitionend', function endTransition() {
  //   navMenu.style.display = 'none';
  //   navMenu.removeEventListener('transitionend', endTransition);
  // });
}

方案二:保留原有的CSS Animation

如果你坚持想用原来的动画方案,那需要等滑出动画执行完再设置display: none,还要让动画结束后保持最终状态:

修改后的CSS

#main-container {
  width: 350px;
  height: 600px;
  border: 1px solid black;
  position: absolute;
  overflow: hidden;
}

#container {
  width: 350px;
  height: 100%;
  position: absolute; /* 修复display:absolute的错误 */
  z-index: 1;
  background: rgba(0, 102, 199, 0.8);
}

#navBtn {
  width: 50px;
  height: 50px;
  background: red;
  position: absolute;
  z-index: 999;
}

#navMenu {
  width: 250px;
  height: 100%;
  background: blue;
  position: absolute;
  z-index: 9999;
  top: 0;
  display: none;
}

#navMenu.open {
  display: block;
  animation-name: slidein;
  animation-duration: .5s;
  animation-fill-mode: forwards; /* 保持动画结束后的状态 */
}

#navMenu.close {
  animation-name: slideout;
  animation-duration: .5s;
  animation-fill-mode: forwards;
}

@keyframes slidein {
  0% {transform: translateX(-250px);}
  100% {transform: translateX(0px);}
}

@keyframes slideout {
  0% {transform: translateX(0px);}
  100% {transform: translateX(-250px);}
}

修改后的JS

var navBtn = document.getElementById("navBtn");
var navMenu = document.getElementById("navMenu");
var container = document.getElementById("container");

navMenu.style.display = "none";

navBtn.addEventListener("click", toggleMenu);
container.addEventListener("click", hideMenu);

function toggleMenu(e) {
  e.stopPropagation(); // 阻止事件冒泡
  if (navMenu.classList.contains('open')) {
    hideMenu();
  } else {
    showMenu();
  }
}

function showMenu() {
  navMenu.classList.remove('close');
  navMenu.style.display = "block";
  // 强制触发浏览器重绘,避免动画不生效
  void navMenu.offsetWidth;
  navMenu.classList.add('open');
  container.style.background = "rgba(0, 102, 199, 1)";
}

function hideMenu() {
  navMenu.classList.remove('open');
  navMenu.classList.add('close');
  container.style.background = "lightblue";
  // 动画结束后再隐藏菜单
  navMenu.addEventListener('animationend', function endAnimation() {
    navMenu.style.display = 'none';
    navMenu.classList.remove('close');
    navMenu.removeEventListener('animationend', endAnimation);
  });
}

两种方案都能实现你要的反向滑出动画,选哪种看你习惯~

内容的提问来源于stack exchange,提问作者Tane

火山引擎 最新活动