使用纯JS动画最大高度?

Joe*_*oey 3 html javascript css css3

我想动画div的高度.这通常通过动画max-height属性在CSS中完成.

但是我需要在JS中这样做.div中填充了频繁更改的动态内容,因此未提前知道实际高度.

这是一个jsfiddle:https://jsfiddle.net/vpknxuk8/

var box = document.getElementById("box");
var button = document.getElementById("button");
var expanded = true;

button.addEventListener('click', function() {
    if (expanded) {
        box.style.maxHeight = 0;
        expanded = false;
    } else {
        box.style.maxHeight = "";
        expanded = true;
    }
});
Run Code Online (Sandbox Code Playgroud)
#box {
  margin-top: 20px;
  border: 1px solid black;
  background-color: #4f88ff;
  width: 200px;
  transition: max-height 0.25s linear;
  overflow: hidden;
}
Run Code Online (Sandbox Code Playgroud)
<button id="button">Click</button>

<div id="box">
  Hello World<br>
  This is dynamic content<br>
  The actual height won't be known ahead of time
</div>
Run Code Online (Sandbox Code Playgroud)

该框应在高度0和默认高度之间转换,但由于某种原因,它不是动画.

StackOverflow上此问题的唯一其他版本属于仅CSS解决方案或jQuery解决方案.

Rok*_*jan 10

不要使用max-height......好吧,除非你想采用产生 CSS的邋solution解决方案来产生延迟差距问题 - 这就是为什么你首先复发JS的原因......

所以使用heighttransition: height不是

首先是一个演示,比一些代码说明:)

function slidetoggle() {

  document.querySelectorAll(this.getAttribute('data-slidetoggle')).forEach(el => {
    const ch = el.clientHeight,
      sh = el.scrollHeight,
      isCollapsed = !ch,
      noHeightSet = !el.style.height;

    el.style.height = (isCollapsed || noHeightSet ? sh : 0) + "px";
    if (noHeightSet) return slidetoggle.call(this);
  });
}


document.querySelectorAll("[data-slidetoggle]").forEach(el => el.addEventListener('click', slidetoggle));
Run Code Online (Sandbox Code Playgroud)
#box1,
#box2 {
  overflow: hidden;
  margin-bottom: 20px;
  background-color: #4f88ff;
  width: 200px;
  transition: height 0.5s;
}
Run Code Online (Sandbox Code Playgroud)
<button data-slidetoggle="#box1">Toggle Box 1</button>

<div id="box1">
  Hello World<br> This is dynamic content<br> The actual height won't be<br> known ahead of time
</div>

<button data-slidetoggle="#box2">Toggle Box 2</button>


<div id="box2">
  Hello World<br> This is dynamic content<br> The actual height won't be<br> known ahead of time<br> bla
  <br> bla
  <br> bla
</div>
Run Code Online (Sandbox Code Playgroud)

解释和一些背景:

如果我们不设置初始高度,CSS高度转换将无法工作.
所以基本上点击 - 如果这样的高度不存在,我们需要通过JS设置它.
在设置了这样的高度之后,转换仍然不起作用,因为浏览器没有时间计算这种元素的盒子模型 - 转换来自:

// (INVALID DEMO) 
//
// Say the element is expanded.
// We need a height to transition-from
el.height = calculatedHeight +"px";  // set CSS height to the calculated value
// Transition to 0px height....
el.height = 0 +"px";
// NO DEAL. our element just snapped to 0 without transition
Run Code Online (Sandbox Code Playgroud)

因此我们需要驻留某种回调.
一种常见的(通常是不准确的)回调是setTimeout

// (INVALID DEMO) 
//
// Say the element is expanded.
// We need a height to transition-from
el.height = calculatedHeight +"px";  // set CSS height to the calculated value
// Transition to 0px height giving the browser some ready-state hack
setTimeout(function() {
    // Eventually the box model will be calculated 
    el.height = 0 +"px";
}, 0);   // <<< PROBLEM: Should we use 0 ? 10? 100? 1000? 
// and our element beautifully transitioned to 0 height.
// Eventually :(
Run Code Online (Sandbox Code Playgroud)

创建此类回调的一种更好方法是在设置初始元素高度后绑定相同的函数:

function slidetoggle() {

  document.querySelectorAll(this.getAttribute('data-slidetoggle')).forEach(el => {
    const ch = el.clientHeight,
      sh = el.scrollHeight,
      isCollapsed = !ch,
      noHeightSet = !el.style.height;

    el.style.height = (isCollapsed || noHeightSet ? sh : 0) + "px";
    if (noHeightSet) return slidetoggle.call(this);
  });
}


document.querySelectorAll("[data-slidetoggle]").forEach(el => el.addEventListener('click', slidetoggle));
Run Code Online (Sandbox Code Playgroud)

提示:如果您需要填充,我的建议是将您的内容包装到另一个子框中 - 使用填充.

上面的代码是概念性的和最小的 - 有很多改进空间,但希望你有了这个想法.


小智 -1

您有 2 个选择:

  • 过渡边框和内边距,使它们全部折叠在一起。

  • 将目标 div 包装在一个新容器中,并为其高度设置动画。您需要溢出:隐藏;。