uniapp微信小程序自定义手风琴组件

文章目录

  • 一、需求与背景
  • 二、效果
  • 三、代码
    • 1.html部分
    • 2.js部分
    • 3.css部分
  • 参考文章


一、需求与背景

这边的需求是做一个手风琴样式的列表,需要有手风琴的动画效果,只能展开一个,列表item的个数和列表item内展开的item个数都是未知的(从后端获取的)。
发现uniapp组件提供的手风琴列表没法自定义title的样式(就是列表item中的样式),所以需要自己实现一个。

二、效果

先上效果
是有逐渐展开的动画效果的,懒得放动图
uniapp微信小程序自定义手风琴组件_第1张图片

三、代码

因为我这里元素过多了有点,所以看起来比较复杂,但其实关键代码就是框架上的那几行,分解来看还是很清晰的

1.html部分

<view class="item" v-for="(item,index) in contentList" :key="index">
                <view @tap="handleClick(index)" class="title">
                  <view class="info-box">
                    <view class="up-box">
                      <view class="name-box">{{item.studentName}}view>
                      <view 
                      v-show="tabIndex == 3"
                      class="flag-box" 
                      :style="{ background: `${item.bgColor}` ,color:`${item.fontColor}`}">
                      {{
                        item.exerciseIntensity === 1
                        ? '适中'
                        : item.exerciseIntensity === 2
                        ? '过量'
                        : item.exerciseIntensity === 3
                        ? '不足'
                        : '未采集'
                      }}view>
                    view>
                    <view class="down-box">
                      <view>学号view>
                      <view style="margin-left:20rpx">{{item.studentCode}}view>
                      <view class="sex">性别   {{item.studentGender===1?'男':item.studentGender===2?'女':'--'}}view>
                    view>
                  view>
                  <img
                    :class="item.open?'down':'up'"
                    :src="require(`@/static/images/icon/down3.png`)"/>
                view>
                <view class="p_item"  :style="{maxHeight:(item.open && item.exerciseIntensity!=null) ? maxHeight : 0}">
                  <view @click="toHeart(item,subIndex)"  class="sub-box" v-for="(sub,subIndex) in item.sportTimeSlotDataList" :key="subIndex" >
                    <view class="up-box">
                      <view>
                        {{sub.sportTimeSlotBeginToEnd}}
                      view>
                    view>
                    <view class="down-box">
                      <view>最高心率   {{sub.maxHeart}}bpmview>
                      <view style="margin-left:50rpx">最低心率   {{sub.minHeart}}bpmview>
                      <view style="margin-left:50rpx">平均心率   {{sub.averageHeart}}bpmview>
                    view>
                  view>
                view>
              view>

2.js部分

contentList就画了个关键结构,其他的按需增加即可

data() {
    return {
      maxHeight: 0,//运动量展开那需要的高度
      contentList: [
	      {
		      open:false,
		      sportTimeSlotDataList:[]
	      },
	      {
		      open:false,
		      sportTimeSlotDataList:[]
	      },
	      {
		      open:false,
		      sportTimeSlotDataList:[]
	      },
      ],
    };
  },
  methods: {
	// 获取dom
    getRect(context, selector) {
      return new Promise((resolve) => {
        const query = uni.createSelectorQuery().in(context);
        query
            .select(selector)
            .boundingClientRect((data) => {
              resolve(data);
            })
            .exec();
      });
    },
    handleClick(index) {//运动量
			this.contentList[index].open = !this.contentList[index].open;
			if (this.contentList[index].open == true) {
				for (var i = 0; i < this.contentList.length; i++) {
					if (i == index) {
						this.contentList[i].open = true;
					} else {
						this.contentList[i].open = false;
					}
				}
			}
      this.getRect(this, '.sub-box').then(res => {
        // 加了20是因为每个item有一个margin-top:20,要算进去,不然就没间隔了,所以如果要是改动的话这块也要跟着改
        var elLength=this.contentList[index].sportTimeSlotDataList.length;
        this.maxHeight = ((parseInt(res.height)+20)* elLength).toString() + 'px';
      })
		},
	}

3.css部分

关键在于动画效果:箭头的up、down,还有子item的展开效果p_item
其他的都是按需求来的都可以改

.item {
		display: flex;
    flex-direction: column; //决定了下拉框在下面
    background-color: #fff;
    .title{
      display: flex;
      flex-direction: row;//左部分是信息,右部分是箭头
      justify-content: space-between;
      .info-box{
        display: flex;
        flex-direction: column;//上部分是姓名和运动量特征,下部分是学号和性别
        width:500rpx;
        justify-content:flex-start;
        .up-box{
          display: flex;
          flex-direction: row;
          margin-top:20rpx;//如果这里改了handleClick算高度那里也要改
          align-items:flex-end;
          .name-box{
            font-weight: 500;
            font-size: 26rpx;
          }
          .flag-box{
            margin-left : 15rpx;
            width: 58rpx;
            height: 32rpx;
            font-size: 18rpx;
            text-align: center;
            line-height: 31rpx;
            border-radius: 6rpx;
          }
          .run-box{
            font-size: 26rpx;
            margin-left:25rpx;
          }
          .divider{
          margin-left:25rpx;
          margin-bottom: 5rpx;
          background: #b7b9b3;
	        width: 1rpx;
	        height: 70%;
          opacity: 0.5;
        }
        }
        .down-box{
          display: flex;
          flex-direction: row;
          font-weight: 500;
          height: 40rpx;
          font-size: 22rpx;
          color: #ACB1B5;
          margin-top:10rpx;
          .sex{
            margin-left: auto ;
            margin-right: 230rpx;
          }
        }
      }
      .up {
        margin-top:50rpx;
        width: 20rpx;
        height: 20rpx;
        opacity: 0.3;
        transition: all ease 0.6s;
        transform: rotate(0deg);
      }

      .down {
        margin-top:50rpx;
        width: 20rpx;
        height: 20rpx;
        opacity: 0.3;
        transition: all ease 0.6s;
        transform: rotate(-180deg);
      }
    }
    .sub-box{
      display: flex;
      flex-direction: column;
      background: #F6F6F6;
      border-radius: 20rpx;
      height: 120rpx;
      margin-top:20rpx;
      .up-box{
        display: flex;
        flex-direction: row;
        align-items:flex-end;
        height: 17rpx;
        font-size: 22rpx;
        font-family: Roboto;
        font-weight: bold;
        margin-top:36rpx;
        margin-left: 35rpx;
        .run-box{
          margin-left:25rpx;
        }
        .divider{
          margin-left:25rpx;
          margin-bottom: 5rpx;
          background: #b7b9b3;
	        width: 1rpx;
	        height: 100%;
          opacity: 0.5;
        }
      }
      .down-box{
        display: flex;
        flex-direction: row;
        height: 18px;
        margin-top:22rpx;
        margin-left: 35rpx;
        font-size: 18rpx;
        font-weight: 500;
        color: #000000;
        opacity: 0.5;
      }
    }
  }
  .p_item {
    overflow: hidden;
    transition: max-height 0.4s ease;
  }

参考文章

本实现方法主要参考了以下几个文章
https://blog.csdn.net/tieniuya/article/details/125769153
https://blog.csdn.net/wh20141212/article/details/107565986
https://blog.csdn.net/sriting/article/details/106111020

你可能感兴趣的:(微信小程序,uni-app,css,vue,javascript)