vue 展开收起的过渡效果

做的一个项目当中需要做一个组件,传入数组,用v-for生成表单,可以展开和收起,展开收起时需要有过渡的效果

在vue里面提供了<transtion></transtion><transition-group></transition-group>两个组件,<transtion>用于普通组件元素,不能用于v-for<transition-group>可用于v-for的场景,是对遍历出来的项做过渡,而我的展开收起需要对整个容器进行过渡,因此需要手动添加过渡效果

这里是对高度变化进行过渡,因此需要满足让高度发生变化这个条件,即对容器设置高度,由于表单是遍历出来的,表单项的布局使用的是栅格

由于容器高度不确定,并且收起按钮位置固定右下角,当剩余位置宽度不够时,另占一行,容器高度需要动态计算,收起时的高度也需要动态计算

思路:给容器设置高度,高度为计算所得,收起时添加一个css类去改变容器高度

image
image

<div class="searform-box">
    <el-form>
        <div :style="{'height': transtionHeight + 'px'}" :class="['transtion', {'expand': !isExpand }]">
            <el-row :gutter="24">
                <el-col
                  v-for="(item, index) in arrays"
                  :class="['search-form-item', {'show': !isExpand && index >= EXPAND_SHOW_COUNT }]"
                  :span="span">内容</el-col>
            </el-row>
        </div>
    </el-form>
</div>

因为收起时的高度是用css去控制的,并且是可变的,因此在css里面用--声明一个变量expandHeight,在.expand{}当中使用var()使用变量

.searform-box{
  --expandHeight: 50px;
  .show{
    opacity: 0;
  }

  .expand{
    height: var(--expandHeight) !important;
  }
  .transtion{
    transition: all 0.3s ease;
    overflow: hidden;
    position: relative;
    .search-form-item{
      height: 50px;
      transition: all 0.3s ease;
    }
  }
}

使用js计算高度

// 行高
public readonly ROW_HEIGHT = 50
// 操作按钮宽度
public readonly OPTION_WIDTH = 220
// 栅格
public readonly ROW_SPAN = 24
// 收起时显示个数
public readonly EXPAND_SHOW_COUNT = 3

// 计算容器高度
public setSearchBoxStyle() {
    let height = 0
    // 容器节点
    const transitionBox = document.getElementsByClassName('transtion')[0] as HTMLElement
    // 循环的项
    const formItems = document.getElementsByClassName('search-form-item')
    if (formItems && formItems.length > 0 && this.isExpand) {
      // 展开
      // 循环出来的所有项所占高度
      height = this.ROW_HEIGHT * Math.ceil((this.span * this.queryItems.length) / this.ROW_SPAN)
      // 最后一项
      const lastFormItem = formItems[formItems.length - 1] as HTMLElement
      // 最后一项右侧到容器右侧的宽度,即所剩宽度
      const width = transitionBox.clientWidth - lastFormItem.offsetLeft - lastFormItem.clientWidth
      // 如果剩余宽度不够,放不下按钮,就再加一行的高度
      if (width < this.OPTION_WIDTH) {
        height += this.ROW_HEIGHT
      }
    } else if (this.queryItems && !this.isExpand) {
      // 收起
      // 收起默认就一行
      height = this.ROW_HEIGHT
      // 收起时最后一项
      const lastIndex = formItems.length > this.EXPAND_SHOW_COUNT ? this.EXPAND_SHOW_COUNT - 1 : formItems.length - 1
      const lastFormItem = formItems[lastIndex] as HTMLElement
      const width = transitionBox.clientWidth - lastFormItem.offsetLeft - lastFormItem.clientWidth
      if (width < this.OPTION_WIDTH) {
        height = this.ROW_HEIGHT * 2
      }
      // 设置css当中expandHeight变量的值
      const searchFormBox = document.getElementsByClassName('searform-box')[0] as HTMLElement
      searchFormBox.style.setProperty('--expandHeight', height + 'px')
    }
    return height
}

/*
 * 表单项栅格计算,根据屏幕宽度动态计算项的所占份额
 */
public setSpan(val: number) {
    if (val > 1440) {
      this.span = 6;
    }
    if (val < 1450 && val > 750) {
      this.span = 8;
    }
    if (val > 550 && val < 750) {
      this.span = 12;
    }
    if (val < 550) {
      this.span = 24;
    }
    this.transtionHeight = this.setSearchBoxStyle()
}

由于是公司项目,完整代码不方便贴,请见谅

posted @ 2022-09-28 14:21  梦羽微澜  阅读(760)  评论(0编辑  收藏  举报