• 下拉列表动画(JavaScript实现)


    要实现一个带动画效果的下拉列表,通常的做法是,将外部容器的高度设为一个固定值,设置其overflow为hidden, 同时为其应用CSS过渡属性,点击相应的按钮后改变外部容器的高度,如下面的实现。

    <div id="p11-1-btn" onclick="toggleByHeight()">▼点我展开</div>
    <ul id="p11-1" style="height: 0px;">
      <li style="background: #FF6666">第一</li>
      <li style="background: #FF9900">第二</li>
      <li style="background: #CCFF00">第三</li>
      <li style="background: #CC3399">第四</li>
    </ul>
    
    function toggleByHeight() {
      const containerStyle =  document.querySelector('#p11-1').style;
      const buttonExpand = document.querySelector('#p11-3-btn');
      if (containerStyle.height == '0px') {
          containerStyle.height = '120px';
          buttonExpand.innerText = '▲点我收起';
      } else {
        containerStyle.height = '0px';
        buttonExpand.innerText = '▼点我展开 ';
      }
    }
    
    #p11-1 {
      overflow:hidden;
      transition: height 1s;
      margin: 0px;
    }
    
    #p11-1 li {
      font-size: 16px;
      color: #ffffff;
      line-height: 30px;
      text-align: center;
      margin: 0px;
    }
    
    #p11-1-btn {
      cursor: pointer;
      background-color: #dcdcdc;
    }
    

    flex-basis

      上面的方法只适用于内部元素高度已知的情况。我们知道每个 li 的行高为30px, 由于 li 没有边框、内边距、外边距,则每个li 的高度就是30px, 全部展开后总高度为150px.
      但是现实中,我们并不总能知道内部元素的高度,而 display: nonedisplay: auto 之间是无法应用过渡效果的(具体为啥我也不知道),因此这种方法就不适用了,那么内部元素的高度应该如何计算出来呢?有人会说可以为父元素设置最大高度 max-height, 这样只要 max-height 的值大于内部元素的总高度就行,但这样做要求我们提供的 max-height 值不能过小也不能过大,过小则内部元素不能全部显示出来,过大则动画会出现延时。

      更好的方法是用JS去计算内部元素的高度,假设有如下的HTML结构,虽然外部容器的高度为0px, 但内部每个元素的高度仍旧为其原来的高度, 只是它被隐藏了起来而已,我们可以通过JS去计算内部元素的总高度。

    <div id="p11-2" style="height: 0px;  overflow: hidden;">
      <div style="height: 40px; padding:10px">第一</div>
      <div style="height: 80px;">第二</div>
      <div style="height: 60px;">第三</div>
    </div>
    
    <script>
      const parent = document.querySelector('#p11-2');
      console.log(parent.style.height)  // 0px
      const childs = document.querySelectorAll('#p11-2 div');
      let totalHeight = 0;
      childs.forEach(child => {
        totalHeight += parseInt(child.style.height);
      });
      console.log(totalHeight)  // 180
    </script>
    

      需要注意的是,你必须使用内联样式为元素指定高度,使用内部样式表或者外部样式表是无法正确通过JS获取高度值的。解决这个问题的办法是,获取该元素的 offsetHeight 而不是 height, offsetHeight 包含该元素的内容高度、垂直内边距和边框,这样一来,不管内部元素有没有内边距、边框,我们总能正确的计算其高度。

    offsetHight

      下面利用这种方法重写一下上面的程序。

    <div id="p11-3-btn" onclick="toggleByOffsetHeight()">▼点我展开</div>
    <ul id="p11-3" style="height: 0px;">
      <li style="background: #FF6666; padding: 10px 0px">第一</li>
      <li style="background: #FF9900; border: solid 5px red">第二</li>
      <li style="background: #CCFF00; padding: 15px 0px">第三</li>
      <li style="background: #CC3399; border: double 3px blue">第四</li>
    </ul>
    
    function toggleByOffsetHeight() {
      const containerStyle = document.querySelector('#p11-3').style;
      const childs =  document.querySelectorAll('#p11-3 li');
      const buttonExpand = document.querySelector('#p11-3-btn');
      let totalHeight = 0;
      childs.forEach(child => {
        totalHeight += parseInt(child.offsetHeight);
      });
      if (containerStyle.height == '0px') {
          containerStyle.height = `${totalHeight}px`;
          buttonExpand.innerText = '▲点我收起';
      } else {
        containerStyle.height = '0px';
        buttonExpand.innerText = '▼点我展开 ';
      }
    }
    
    #p11-3 {
      overflow:hidden;
      transition: height 1s;
      margin: 0px;
    }
    
    #p11-3 li {
      font-size: 16px;
      color: #ffffff;
      line-height: 30px;
      text-align: center;
      margin: 0px;
    }
    
    #p11-3-btn {
      cursor: pointer;
      background-color: #dcdcdc;
    }
    

    flex-basis

      可以看到,无论内部元素占据的高度是什么,我们总能实现一个流畅的下拉列表过渡动画。

    该篇博客内的代码已同步到Github

    参考资料:
    [1]. MDN文档 https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/offsetHeight

  • 相关阅读:
    正则表达式
    scrollTop
    css3
    错误整理
    jquery-2
    vscode_修改字体,使用Fira Code
    实例_一个循环嵌套函数
    js_getComputed方法和style属性关于读取样式的区别
    html_html5增强的文件上传域_使用FileReader读取文件内容
    html_html5增强的文件上传域_FileList对象与File对象
  • 原文地址:https://www.cnblogs.com/nkqlhqc/p/12598601.html
Copyright © 2020-2023  润新知