这是此前项目要实现的效果,一个简单的折叠框,但为了让其使用更加的顺滑,想通过加入transition过渡动画让其展开更加的舒服。

原效果.png

但是有一个致命的问题,transition过渡动画是必须得提前知道元素的起止属性,即展开前高度和展开后高度,因为里面内容是动态的,所以无法直接给出最终高度。使用max-height属性能实现过渡动画,但是效果太差,所以采用了js计算高度的方式。

首先给父容器即折叠栏赋予overflow: hidden;和固定的高度的classflod,以及过渡动画transition: height .75s;,子元素即内容赋予visibility: hidden;,如果所示。

.collapse {
  background-color: white;
  border-radius: 40rpx;
  box-sizing: border-box;
  overflow: hidden;
  transition: all .75s;
}
.fold {
  height: 80rpx !important;
}

折叠.png

折叠栏在折叠的情况下:
触发点击事件=>
移除classflod=>
动态加载元素=>
计算出内容元素高度=>
赋予折叠栏新高度(折叠下高度+元素内容高度) && 显示内容元素(visibility: visible;)

折叠栏在展开的情况下:
触发点击事件=>
计算当前总高度并赋予折叠栏=>
移除内容元素=>
添加classflod

以下是在微信小程序内的实现方式
wxml

<view class='collapse {{fold || hide ? "fold" : ""}}' style='height: {{height}};'>
  <view class='top-container' bindtap='fold'>
    <view class='title'>{{title}}</view>
    <view class='angle'>
      <view wx:if='{{fold}}' class='fa fa-angle-down'></view>
      <view wx:else class='fa fa-angle-up'></view>
    </view>
  </view>
  <view class='content-container {{hide ? "hidden" : ""}}' wx:if='{{!fold}}'>
    <slot></slot>
  </view>
</view>

wxss

.collapse {
  background-color: white;
  border-radius: 40rpx;
  box-sizing: border-box;
  overflow: hidden;
  transition: all .75s;
}

.fold {
  height: 80rpx !important;
}

.collapse .top-container {
  width: 100%;
  height: 80rpx;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-sizing: border-box;
  padding: 0 40rpx;
}

.collapse .top-container .title {
  color: #353535;
  font-size: 32rpx;
}

.collapse .top-container .angle {
  font-size: 40rpx;
}

.collapse .content-container {
  border-top: 1px solid rgb(240, 240, 240);
}

.hidden {
  visibility: hidden;
}

js

fold() {
  if (this.data.fold) {
    this.setData({
      fold: false,
      hide: true
    })
    let query = wx.createSelectorQuery().in(this) //in!
    query.select(`.top-container`).boundingClientRect()
    query.select(`.content-container`).boundingClientRect()
    query.exec(res => {
      let height = res[0].height + res[1].height
      height += 'px'
      this.setData({
        height: height,
        hide: false
      })
    })
  } else {
    let query = wx.createSelectorQuery().in(this)
    query.select(`.top-container`).boundingClientRect()
    query.select(`.content-container`).boundingClientRect()
    query.exec(res => {
      let height = res[0].height + res[1].height
      height += 'px'
      this.setData({
        height: height,
      })
      setTimeout(() => {
        this.setData({
          fold: true
        })
      }, 50)
    })
  }
}

最终效果

最终效果.gif