最近开发的一个小程序中涉及一个答题页面,打算使用小程序的swiper组件开发,题目可能数量过多,使用swiper一次性加载会造成卡顿,于是进行了一些优化

解决思路:页面只展示3个swiper-item组件(小程序视频轮播插件受到的启发),每次轮播变化,都截取总数据里面的3条进行展示

观察规律:画了个简单草图,大家可以看下,每次轮播索引变化后,计算出当前索引、前一个索引值、后一个索引值,以及分别对应到数据列表上的索引和值

在这里插入图片描述

代码实现

<template>
  <view class="index-box">
    <swiper class="swipe" :circular="circular" :current="swipeActiveIndex" @change="swipeChange">
      <swiper-item v-for="(item, index) in swipeList" :key="index">
        <view class="swipe-item">{{ item }}</view>
      </swiper-item>
    </swiper>
  </view>
</template>
<script>
export default {
  data() {
    return {
      circular: true, // 是否可以循环滚动
      swipeActiveIndex: 0, // 当前轮播图激活索引
      currentIndex: 0, // 当前展示数据在列表中的索引值
      swipeLength: 3, // 总的轮播图数量
      dataList: [1, 2, 3, 4, 5, 6, 7] // 数据列表
    }
  },
  computed: {
    swipeList() {
      // 获取当前值、下一个值、上一个值
      let currentValue = this.dataList[this.currentIndex]
      let nextValue = this.dataList[this.getDataIndex(this.currentIndex + 1)]
      let prevValue = this.dataList[this.getDataIndex(this.currentIndex - 1)]

      // 获取当前轮播索引对应的值、下个索引对应的值、上个索引对应的值
      let list = new Array(3)
      list[this.swipeActiveIndex] = currentValue
      list[this.getSwipeIndex(this.swipeActiveIndex + 1)] = nextValue
      list[this.getSwipeIndex(this.swipeActiveIndex - 1)] = prevValue
      return list
    }
  },
  methods: {
    swipeChange(event) {
      let current = Number(event.detail.current)
      if ([1, 1 - this.swipeLength].includes(current - this.swipeActiveIndex)) {
      	// 向左滑动
        this.currentIndex = this.getDataIndex(this.currentIndex + 1)
      } else {
      	// 向右滑动
        this.currentIndex = this.getDataIndex(this.currentIndex - 1)
      }
      this.swipeActiveIndex = current
    },
    // 获取当前数据列表的索引
    getDataIndex(index) {
      if (index < 0) {
        // 小于零,返回数据列表末尾索引
        return this.dataList.length - 1
      } else if (index >= this.dataList.length) {
        // 等于(或大于,一般不会)数据列表长度,返回数据首位索引
        return 0
      } else {
        return index
      }
    },
    getSwipeIndex(index) {
      if (index < 0) {
        return this.swipeLength - 1
      } else if (index >= this.swipeLength) {
        return 0
      } else {
        return index
      }
    }
  }
}
</script>
<style scoped lang="scss">
.index-box {
  width: 100%;

  .swipe {
    width: 100%;
    height: 300rpx;

    &-item {
      display: flex;
      width: 100%;
      height: 100%;
      font-size: 80rpx;
      color: #fff;
      background: #222;
      align-items: center;
      justify-content: center;
    }
  }
}
</style>

关于如何在答题后或者点击某个按钮后自动进入下一题,新增currentSwipeIndex参数、nextSwipe方法,附上之前涉及项目中的解决方法

<template>
  <view class="index-box u-safe-area-inset-bottom">
    <c-space />
    <swiper
      class="swipe"
      :current="currentSwipeIndex"
      :circular="circular"
      @animationfinish="swipeChange"
    >
      <swiper-item v-for="(item, index) in swipeList" :key="index">
        <answer-item :item="item" @next="nextSwipe" />
      </swiper-item>
    </swiper>
    <view class="submit-btn">
      <view class="submit-btn__wrap" @click="onSubmit">提交</view>
    </view>
    <view class="paging">{{ currentIndex + 1 }} / {{ dataList.length }}</view>
  </view>
</template>
<script>
  import AnswerItem from './components/AnswerItem'
  import { mapState } from 'vuex'
  export default {
    components: { AnswerItem },
    data() {
      return {
        currentSwipeIndex: 0,
        circular: true, // 是否可以循环滚动
        swipeActiveIndex: 0, // 当前轮播图激活索引
        currentIndex: 0, // 当前展示数据在列表中的索引值
        swipeLength: 3, // 总的轮播图数量
        // dataList: [1, 2, 3, 4, 5, 6, 7], // 数据列表
      }
    },
    computed: {
      ...mapState({
        dataList: (state) => state.vuex_assess_topic,
        answerList: (state) => state.vuex_assess_answer,
        assessInfo: (state) => state.vuex_assess_info,
        assessEmpty: (state) => state.vuex_assess_empty,
      }),
      swipeList() {
        // 获取当前值、下一个值、上一个值
        let currentValue = this.dataList[this.currentIndex]
        let nextValue = this.dataList[this.getDataIndex(this.currentIndex + 1)]
        let prevValue = this.dataList[this.getDataIndex(this.currentIndex - 1)]

        // 获取当前轮播索引对应的值、下个索引对应的值、上个索引对应的值
        let list = new Array(3)
        list[this.swipeActiveIndex] = currentValue
        list[this.getSwipeIndex(this.swipeActiveIndex + 1)] = nextValue
        list[this.getSwipeIndex(this.swipeActiveIndex - 1)] = prevValue
        return list
      },
    },
    onLoad() {
      uni.setNavigationBarTitle({
        title: this.assessInfo.title,
      })
    },
    methods: {
      swipeChange(event) {
        let current = Number(event.detail.current)
        if ([1, 1 - this.swipeLength, 0].includes(current - this.swipeActiveIndex)) {
          this.currentIndex = this.getDataIndex(this.currentIndex + 1)
        } else {
          this.currentIndex = this.getDataIndex(this.currentIndex - 1)
        }
        this.swipeActiveIndex = current
      },
      nextSwipe() {
        setTimeout(() => {
          this.currentSwipeIndex = this.getSwipeIndex(this.swipeActiveIndex + 1)
        }, 600)
      },
      // 获取当前数据列表的索引
      getDataIndex(index) {
        if (index < 0) {
          // 小于零,返回数据列表末尾索引
          return this.dataList.length - 1
        } else if (index >= this.dataList.length) {
          // 等于(或大于,一般不会)数据列表长度,返回数据首位索引
          return 0
        } else {
          return index
        }
      },
      getSwipeIndex(index) {
        if (index < 0) {
          return this.swipeLength - 1
        } else if (index >= this.swipeLength) {
          return 0
        } else {
          return index
        }
      },
      /*提交*/
      onSubmit() {
        const valid = this.answerList.some((item) => !item)
        if (valid) {
          this.$toast('请完成所有题目')
          return
        }
        this.$loading()
        this.$request
          .post('study.subAnswer', {
            study_id: this.assessInfo.id,
            answer: this.answerList.map((item) => (item === this.assessEmpty ? '' : item)),
          })
          .then(() => {
            this.$hide()
            this.$linkTo('/package/echarts/assess-result/index')
          })
          .catch((err) => {
            this.$toast(err)
          })
      },
    },
  }
</script>
<style>
  page {
    width: 100%;
    height: 100%;
  }
</style>
<style scoped lang="scss">
  @import 'static/styles/mixin';

  .index-box {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    background: #f7f7f7;

    .swipe {
      width: 100%;
      flex: 1;
      overflow: hidden;
    }

    .paging {
      display: flex;
      width: 100%;
      height: 112rpx;
      font-size: 26rpx;
      align-items: center;
      justify-content: center;
    }

    .submit-btn {
      width: 100%;
      padding: 0 30rpx;

      &__wrap {
        @include flex-row-center;

        width: 100%;
        height: 100rpx;
        font-size: 30rpx;
        font-weight: bold;
        color: #fff;
        background: linear-gradient(90deg, #ff6155, #fb1a26);
        border-radius: 16rpx;
      }
    }

    .submit-disabled {
      .submit-btn__wrap {
        position: relative;

        &::after {
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background: rgba(0, 0, 0, 0.2);
          border-radius: 16rpx;
          content: '';
        }
      }
    }
  }
</style>

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐