如何用纯JS实现未知高度的jQuery slideDown()方法

6
我正在尝试实现一个“切换可见性并带有滑动效果”的功能,类似于jQuery的slideDown(),但是使用普通的JS。我可以随时间动画化值,没有问题,但是当应该变得可见的元素的高度未知时,我该怎么办?现有的样本解决方案似乎总是将max-height值动画化到固定值,但我需要动画化到先前未知的值(高度)。(如果有一种使用css3实现这一点的方法,我也会很好奇!)
6个回答

14

将您的元素高度设置为0,隐藏溢出,并使用CSS3转换来处理动画:

.container {
  height: 0px;
  overflow: hidden;
  transition: all 1000ms;
}

您可以基于元素的 scrollHeight 轻松地对其进行动画处理:

var container= document.querySelector('.container');
container.style.height= container.scrollHeight + 'px';

片段

document.querySelector('button').addEventListener('click', function() {
  var container= document.querySelector('.container');
  container.style.height= container.scrollHeight + 'px';
});
.container {
  font: 24px verdana;
  background: #dfd;
  height: 0px;
  overflow: hidden;
  transition: all 1000ms;
}
<button>
 Slide Down
</button>

<div class="container">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>

Fiddle


1
我之前对scrollHeight不是很清楚,但我现在很喜欢它!"Element.scrollHeight只读属性是元素内容高度的衡量标准,包括因溢出而屏幕上不可见的内容。" - Hoff
1
我不常在互联网上承认有人比我聪明,但作为现在正需要的人,我觉得这个太聪明了。+1 - JR Halchak
1
这太棒了,终于让我能够创建一个Vue2过渡效果,使用CSS过渡来向下滑动表格单元格的内容(只需少量JS)。绝对精彩,谢谢! - lifo

1

如果<input type="button" id="slide" value =" Slide Down "/>有父元素,你可以进行测试,如果他没有父元素(即他的父元素是<body>),你可以这样做:

var maxheight = $(window).height();

请看链接1


1

document.getElementsByTagName('div')[0].onclick = function() {
  this.style.height = this.offsetHeight + 'px';
  var that = this;
  setTimeout(function() { that.style.height = '0'; }, 10);
};
div {
  width: 50px;
  background-color: yellow;
  overflow: hidden;
  transition: height 300ms ease;
}
<div>
  <p>Let us not talk falsely now</p>
</div>


1
首先,在页面加载时需要检测元素的高度。然后将该高度设置为“max-height”CSS属性。
现在,您可以使用一些CSS和JS来上下滑动:

window.addEventListener("load", () => {
  var div = document.getElementById("slindingDiv");
  // set max height
  div.style.setProperty("max-height", div.offsetHeight + "px");
  // default: hide 
  div.classList.add("up");
  // button logic
  document.getElementById("toggle").onclick = () => {
    if (div.classList.contains("up")) {
      div.classList.remove("up");
    } else {
      div.classList.add("up");
    }
  };
});
#slindingDiv {
  transition: max-height 0.5s ease-in-out;
  overflow: hidden;
  background: antiquewhite;
  /* YOU CAN PLAY WITH WIDTH */
  width: 75%;
}
/* You just have to add this class to make it slide up */

#slindingDiv.up {
  max-height: 0 !important;
}
<div id="slindingDiv">
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus rutrum mi vel mauris ultricies, id vehicula mi hendrerit. Pellentesque placerat diam vel fermentum fermentum. Nulla eget odio a ipsum posuere dapibus. Ut sollicitudin tempor nibh, eu
    convallis turpis iaculis tincidunt. Integer luctus ipsum vestibulum diam laoreet, at ornare felis tincidunt. Mauris dapibus diam ut ultrices ornare. Quisque nec risus in neque consequat efficitur vitae non turpis. Vivamus posuere sapien ac tellus
    euismod volutpat eu id mauris. Nunc vel convallis nisi. Quisque convallis fringilla porttitor. Donec id consectetur nisi. Aliquam id dui ornare, efficitur erat sed, vestibulum nisi. Donec suscipit fringilla dolor, sed ullamcorper leo varius ac. Vestibulum</p>
</div>
<button id="toggle">Toggle slide</button>


1

我发现大多数解决方案都是基于“height”属性的动画,由于浏览器重新绘制进程(特别是在移动设备上),这可能会导致卡顿。因此,我建议使用“transition”和“opacity”属性的动画来模拟高度的变化;

示例:https://jsfiddle.net/av6207fy/3/

这种解决方案会更加流畅,因为它使用了“transform”和“opacity”属性的动画。您可以在这里阅读更多信息 http://www.html5rocks.com/en/tutorials/speed/high-performance-animations/

HTML

<div class="slider">
  <div class="slider-header">
    Click to toggle
  </div>
  <div class="slider-body">
    "At vero eos et accusamus et iusto odio dignissimos ducimus qui 
    blanditiis praesentium voluptatum deleniti atque corrupti quos dolores 
    et quas molestias excepturi sint occaecati cupiditate non provident, 
    similique sunt in culpa qui officia deserunt mollitia animi, id est 
    laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita
    distinctio. Nam libero tempore, cum soluta nobis est eligendi optio 
    cumque nihil impedit quo minus id quod maxime placeat facere possimus, 
    omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem 
    quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet     
    ut et voluptates repudiandae sint et molestiae non recusandae. Itaque 
    earum rerum hic tenetur a sapiente delectus, ut aut reiciendis 
    voluptatibus maiores alias consequatur aut perferendis doloribus 
    asperiores repellat."
  </div>
</div>

JS:

$(function(){
  $('.slider').on('click', '.slider-header', function(e){
      $(e.delegateTarget).toggleClass('expanded');
  });
});

CSS:
* {
  box-sizing: border-box;
}

.slider {
  position: relative;
  overflow: hidden;
  margin: 40px;
}

.slider .slider-header {
  width: 100%;
  height:40px;
  text-align: center;
  line-height: 40px;
  background: green;
  color: white;
  cursor: pointer;
  position: relative;
  z-index: 2;
}

.slider .slider-body {
  width: 100%;
  padding: 20px;
  position: relative;
  z-index: 1;
  background: red;
  color: white;
  text-align: center;

  -ms-transform: translate3d(0, -140px, 0);
  -o-transform: translate3d(0, -140px, 0);
  -moz-transform: translate3d(0, -140px, 0);
  transform: translate3d(0, -140px, 0);
  opacity: 0;

  -o-transition: all 0.2s ease-out;
  -moz-transition: all 0.2s ease-out;
  -webkit-transition: all 0.2s ease-out;
  transition: all 0.2s ease-out;
}

.slider.expanded .slider-body {
  -webkit=transform: translate3d(0, 0, 0);
  -ms-transform: translate3d(0, 0, 0);
  -o-transform: translate3d(0, 0, 0);
  -moz-transform: translate3d(0, 0, 0);
  transform: translate3d(0, 0, 0);
  opacity: 1;
}

据我所知,CSS转换和动画通常比使用良好的JS动画库动画要慢(目前而言,这种情况可能会在未来发生改变)。 - Apolo
JavaScript动画(例如更改offsetHeight,offsetWidth,top,left,margins等)从先验上讲不能比CSS的“opacity”和“transform”属性的动画更快,因为它会导致浏览器中的“重绘”->“重新计算样式”。请仔细阅读我的答案。 在这里,您还可以了解有关CSS动画性能的信息:https://developers.google.com/web/fundamentals/design-and-ui/animations/animations-and-performance - Evgeny Sorokin
有趣的资源。然而,我不确定Javascript slideDown会影响性能(正如我所说,使用良好的JS动画库)。你应该看看http://codepen.io/GreenSock/pen/pmknI/ Velocity(轻量级)和GSAP(更大但用于不同的需求)在left属性上执行操作非常出色(即使像你所说的那样需要浏览器重绘)。 - Apolo
1
非常有趣。这次讨论引导我查看了这篇文章(https://davidwalsh.name/css-js-animation)。在那里,你可以找到解释为什么一些JS库可以达到CSS动画的水平。但是,在任何情况下,要实现简单的滑块(当您不需要完全控制渲染-暂停、恢复、重播等)时,您不应该使用庞大的库——在这里,CSS就足够了。 - Evgeny Sorokin
我同意这一点。但是,如果 OP 的网站已经有很多动画,他应该看看 Velocity.js,只需下载 7kb 就可以获得巨大的提升。 - Apolo

0

两个纯CSS(无JavaScript)的替代方案:

1 - 隐藏复选框(允许同时打开多个框):

input[type=checkbox] {
  display: none;  
}

jsfiddle DEMO #1

2 - 暗藏的单选按钮(“单选”行为):

input[type=radio] {
  display: none;  
}

jsfiddle DEMO #2

Javascript改进:

2b - 带有第二次点击取消选择的“单选”行为的秘密单选按钮:

var allRadios = document.getElementsByName('image');
var booRadio;
var x = 0;
for(x = 0; x < allRadios.length; x++){

allRadios[x].onclick = function() {
      if(booRadio == this){
          this.checked = false;
          booRadio = null;
      }else{
          booRadio = this;
      }
  };
}

jsfiddle演示 #2B


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接