为啥我的 Accordion 关闭动画没有触发?它打开(有动画)但没有动画关闭

Posted

技术标签:

【中文标题】为啥我的 Accordion 关闭动画没有触发?它打开(有动画)但没有动画关闭【英文标题】:Why is my Accordion closing animation not firing? It opens (with animation) but closes without animation为什么我的 Accordion 关闭动画没有触发?它打开(有动画)但没有动画关闭 【发布时间】:2021-10-31 17:46:33 【问题描述】:

这是我的问题的Fiddle(单击“Werknemers”或“Verzuimdossiers”旁边的图片)。

我有一个侧边栏,其中有些项目有子内容,有些则没有。所以我用 subnav 项目制作了一个手风琴。问题是开场动画效果很好。但是,关闭动画没有被触发。

这可能是什么问题?

参考代码

openSubnav = (evt, subNavName) => 
  let i, subnavContent, subnavLinks;

  //Check if the current accordion is clicked again to close it.
  const subNav = document.getElementById(subNavName)
  if (getComputedStyle(subNav).display === 'block') 
    subNav.style.display = 'none'
    evt.currentTarget.className = evt.currentTarget.className.replace(" subnav-isActive", "");
    subNav.style.maxHeight = null;
    return
  
  //hide alle subnav content
  subnavContent = document.getElementsByClassName("subnav-content");
  for (i = 0; i < subnavContent.length; i++) 
    subnavContent[i].style.display = "none";

  
  //delete the subnav-isActive class
  subnavLinks = document.getElementsByClassName("subnav-item");
  for (i = 0; i < subnavLinks.length; i++) 
    subnavLinks[i].className = subnavLinks[i].className.replace(" subnav-isActive", "");
  
  //Display the content
  subNav.style.display = "block";
  //Add the subnav-isActive class
  evt.currentTarget.className += " subnav-isActive";

  //If there currently is a max-height on the element, delete it.
  if (subNav.style.maxHeight) 
    subNav.style.maxHeight = null;
  
  subNav.style.maxHeight = subNav.scrollHeight + "px";
* 
  margin: 0;
  padding: 0;
  box-sizing: border-box;


.root 
  display: flex;
  font-family: 'Poppins', sans-serif;


nav 
  -webkit-user-select:none;
  -moz-user-select:none;
  -ms-user-select:none;
  -o-user-select:none;
  user-select:none;


.icon-container 
  width: 60px; 
  height: 50px; 
  display: flex; 
  justify-content: center; 
  align-items: center;


/* .sidebar:hover 
  width: 250px;
  overflow: visible;
 */

.sidebar 
  width: 250px;


.sidebar 
  background-color: #8dc4d9;
  position:absolute;
  top:0;
  bottom:0;
  height:100%;
  left:0;
  /* width:60px; */
  overflow:hidden;
  -webkit-transition:width .05s linear;
  transition:width .05s linear;


.sidebar>ul 
  margin: 10px 0;


.sidebar li 
  width:250px;


.sidebar li>span 
  position: relative;
  display: table;
  border-collapse: collapse;
  border-spacing: 0;
  font-size: 14px;
  transition: all .1s linear;


.sidebar .nav-text 
  display: table-cell;
  vertical-align: middle;
  /* 250px breed totaal - 60px breed icoon = 190 */
  width: 190px;


.sidebar .nav-dropdown 
  display: table-cell;
  vertical-align: middle;
  cursor: pointer;
  padding-right: 20px;
  padding-top: 8px;


.sidebar .nav-dropdown img 
  transform: rotate(270deg);
  transition: transform .3s ease;


.sidebar .nav-dropdown.subnav-isActive img 
  transform: rotate(360deg);


.user 
  margin-bottom: 20px;


.sidebar li:hover>span 
  background-color:#76abbf;


.subnav-content 
  display: none;
  /* 17px omdat de afbeelding 24x24 is en de breedte van de sidebar 60px. 
     Met de afbeelding houd je dus 17px aan beiden kanten over. */
  padding: 10px 17px;
  background-color:#76abbf;
  list-style: none;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;


.content 
  width: calc(50% - 30px);
  background-color: #f3f6f9;


.preview 
  width: calc(50% - 30px);
  background-color: #f3f6f9;
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="style.css">
  <script src="script.js"></script>
  <title>Sidebar</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet">
</head>

<body>
  <div class="root">
    <nav class="sidebar">
      <ul>
        <li class="user">
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/user32.png" >
            </div>
            <span class="nav-text">
              Mijn account
            </span>
          </span>
        </li>
        <li>
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/bureaublad24.png" >
            </div>
            <span class="nav-text">
              Dashboard
            </span>
          </span>
        </li>
        <li class="has-subnav">
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/werknemers24.png" >
            </div>
            <span class="nav-text">
              Werknemers
            </span>
            <span class="nav-dropdown subnav-item" onclick="openSubnav(event, 'Werknemers')">
              <img src="./icons24/DropdownArrow16.png">
            </span>
          </span>
          <ul id="Werknemers" class="subnav-content">
            <li>kaas</li>
            <li>brood</li>
            <li>eieren</li>
          </ul>
        </li>
        <li>
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/verzuimdossiers24.png" >
            </div>
            <span class="nav-text">
              Verzuimdossiers
            </span>
            <span class="nav-dropdown subnav-item" onclick="openSubnav(event, 'Verzuimdossiers')">
              <img src="./icons24/DropdownArrow16.png">
            </span>
          </span>
          <ul id="Verzuimdossiers" class="subnav-content">
            <li>boter</li>
            <li>friet</li>
            <li>pasta</li>
          </ul>
        </li>
        <li>
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/trajecten24.png" >
            </div>
            <span class="nav-text">
              Trajecten
            </span>
          </span>
        </li>
        <li>
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/projecten24.png" >
            </div>
            <span class="nav-text">
              Projecten
            </span>
          </span>
        </li>
      </ul>
    </nav>
    <div class="content">
      Content
    </div>
    <div class="preview">
      Preview
    </div>
  </div>
</body>

</html>

【问题讨论】:

【参考方案1】:

您需要在display: none 之前设置超时,以便有时间执行结束动画。

就像这段代码:

  const subNav = document.getElementById(subNavName)
  if (getComputedStyle(subNav).display === 'block') 
    evt.currentTarget.className = evt.currentTarget.className.replace(" subnav-isActive", "");
    subNav.style.maxHeight = null;
    setTimeout(function()subNav.style.display = 'none';, 100);
    return
  

这里你有完整的正确代码(idk 为什么,但你需要展开 sn-p 才能看到它的工作,点击 Run code sn-p 然后 Full page 链接):

openSubnav = (evt, subNavName) => 
  let i, subnavContent, subnavLinks;

  //Check if the current accordion is clicked again to close it.
  const subNav = document.getElementById(subNavName)
  if (getComputedStyle(subNav).display === 'block') 
    evt.currentTarget.className = evt.currentTarget.className.replace(" subnav-isActive", "");
    subNav.style.maxHeight = null;
    setTimeout(function()subNav.style.display = 'none';, 100);
    return
  
  //hide alle subnav content
  subnavContent = document.getElementsByClassName("subnav-content");
  for (i = 0; i < subnavContent.length; i++) 
    subnavContent[i].style.display = "none";

  
  //delete the subnav-isActive class
  subnavLinks = document.getElementsByClassName("subnav-item");
  for (i = 0; i < subnavLinks.length; i++) 
    subnavLinks[i].className = subnavLinks[i].className.replace(" subnav-isActive", "");
  
  //Display the content
  subNav.style.display = "block";
  //Add the subnav-isActive class
  evt.currentTarget.className += " subnav-isActive";

  //If there currently is a max-height on the element, delete it.
  if (subNav.style.maxHeight) 
    subNav.style.maxHeight = null;
  
  subNav.style.maxHeight = subNav.scrollHeight + "px";
* 
  margin: 0;
  padding: 0;
  box-sizing: border-box;


.root 
  display: flex;
  font-family: 'Poppins', sans-serif;


nav 
  -webkit-user-select:none;
  -moz-user-select:none;
  -ms-user-select:none;
  -o-user-select:none;
  user-select:none;


.icon-container 
  width: 60px; 
  height: 50px; 
  display: flex; 
  justify-content: center; 
  align-items: center;


/* .sidebar:hover 
  width: 250px;
  overflow: visible;
 */

.sidebar 
  width: 250px;


.sidebar 
  background-color: #8dc4d9;
  position:absolute;
  top:0;
  bottom:0;
  height:100%;
  left:0;
  /* width:60px; */
  overflow:hidden;
  -webkit-transition:width .05s linear;
  transition:width .05s linear;


.sidebar>ul 
  margin: 10px 0;


.sidebar li 
  width:250px;


.sidebar li>span 
  position: relative;
  display: table;
  border-collapse: collapse;
  border-spacing: 0;
  font-size: 14px;
  transition: all .1s linear;


.sidebar .nav-text 
  display: table-cell;
  vertical-align: middle;
  /* 250px breed totaal - 60px breed icoon = 190 */
  width: 190px;


.sidebar .nav-dropdown 
  display: table-cell;
  vertical-align: middle;
  cursor: pointer;
  padding-right: 20px;
  padding-top: 8px;


.sidebar .nav-dropdown img 
  transform: rotate(270deg);
  transition: transform .3s ease;


.sidebar .nav-dropdown.subnav-isActive img 
  transform: rotate(360deg);


.user 
  margin-bottom: 20px;


.sidebar li:hover>span 
  background-color:#76abbf;


.subnav-content 
  display: none;
  /* 17px omdat de afbeelding 24x24 is en de breedte van de sidebar 60px. 
     Met de afbeelding houd je dus 17px aan beiden kanten over. */
  padding: 10px 17px;
  background-color:#76abbf;
  list-style: none;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;


.content 
  width: calc(50% - 30px);
  background-color: #f3f6f9;


.preview 
  width: calc(50% - 30px);
  background-color: #f3f6f9;
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="style.css">
  <script src="script.js"></script>
  <title>Sidebar</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet">
</head>

<body>
  <div class="root">
    <nav class="sidebar">
      <ul>
        <li class="user">
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/user32.png" >
            </div>
            <span class="nav-text">
              Mijn account
            </span>
          </span>
        </li>
        <li>
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/bureaublad24.png" >
            </div>
            <span class="nav-text">
              Dashboard
            </span>
          </span>
        </li>
        <li class="has-subnav">
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/werknemers24.png" >
            </div>
            <span class="nav-text">
              Werknemers
            </span>
            <span class="nav-dropdown subnav-item" onclick="openSubnav(event, 'Werknemers')">
              <img src="./icons24/DropdownArrow16.png">
            </span>
          </span>
          <ul id="Werknemers" class="subnav-content">
            <li>kaas</li>
            <li>brood</li>
            <li>eieren</li>
          </ul>
        </li>
        <li>
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/verzuimdossiers24.png" >
            </div>
            <span class="nav-text">
              Verzuimdossiers
            </span>
            <span class="nav-dropdown subnav-item" onclick="openSubnav(event, 'Verzuimdossiers')">
              <img src="./icons24/DropdownArrow16.png">
            </span>
          </span>
          <ul id="Verzuimdossiers" class="subnav-content">
            <li>boter</li>
            <li>friet</li>
            <li>pasta</li>
          </ul>
        </li>
        <li>
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/trajecten24.png" >
            </div>
            <span class="nav-text">
              Trajecten
            </span>
          </span>
        </li>
        <li>
          <span>
            <div class="icon-container">
              <img class="nav-icon" src="./icons24/projecten24.png" >
            </div>
            <span class="nav-text">
              Projecten
            </span>
          </span>
        </li>
      </ul>
    </nav>
    <div class="content">
      Content
    </div>
    <div class="preview">
      Preview
    </div>
  </div>
</body>

</html>

【讨论】:

【参考方案2】:

原因是因为你的动画需要一些时间来执行,但是你在你的动画有机会被渲染之前分配了display: none

【讨论】:

以上是关于为啥我的 Accordion 关闭动画没有触发?它打开(有动画)但没有动画关闭的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 AngularJS ajax 自动触发,即使我没有调用它?

我正在使用点击事件触发CSS动画,为啥再次点击时动画不会再次运行?

如果应用了 css 过渡,为啥动画回调函数会立即触发?

动画不触发重新渲染

1个元素JS,CSS的多个动画[关闭]

如何平滑地将 CSS 动画恢复到当前状态?