mpvue微信小程序长列表

mpvue微信小程序长列表

解决数据过多导致小程序白屏等问题。优化性能。

github demo地址

<scroll-view
    scroll-y
    class="main-box"
    :style="{height:systemHeight+'px'}"
    @scrolltolower="handleToBottom"
    @scroll="onScroll"
    lower-threshold="300rpx"
  >
    <!-- 全部内容盒子高度 -->
    <div class="scroll-box" :style="{height:allBoxHeight+'px'}">
      <!-- 可视区域盒子 -->
      <div class="scroll-main" :style="{top:top+'px'}">
        <card v-for="(item,i) in forEachArr" :key="i" :text="item" />
      </div>
    </div>
  </scroll-view>

话不多说,先贴代码
使用小程序scroll-view标签,监听滚动onScroll和触底事件handleToBottom,设置距离底部 lower-threshold="300rpx"时触发触底事件,使用变量systemHeight去适应各设备屏幕大小。其中card 是封装的内容组件,通过数据循环出来。


在onLoad生命周期中获取各设备屏幕大小并赋值给变量systemHeight

onLoad() {
    this.queryList();// 请求数据
    wx.getSystemInfo({
      success: res => {
        this.systemHeight = res.windowHeight;
      }
    });
  }

全部内容盒子高度由请求回的所有数据条数*每条数据盒子card组件的高控制(接口使用的之前在网上找到的一位哥们的,不知道是否涉权啥的,如有请联系删除:3144739622@qq.com,多谢)

// 请求数据
    queryList() {
      if (!this.isdisabaled) {
        wx.showLoading({ title: "加载中..." });
        this.isdisabaled = true;
        wx.request({
          url: "https://w.taopaitang.com/api/discover",
          method: "GET",
          data: this.queryData,
          header: {
            "content-type": "application/json" // 默认值
          },
          dataType: "json",
          success: res => {
            wx.hideLoading();
            if (res.data.code !== 200) {
              wx.showToast({
                title: res.data.message,
                icon: "none",
                duration: 2000,
                mask: true
              });
            } else {
              let data = res.data.data.items;
              if (this.queryData.page === 1) {
                this.allDataArr = data;
              } else {
                this.allDataArr = this.allDataArr.concat(data);
              }
              this.computedShowData();
              this.isdisabaled = false;
            }
          }
        });
      }
    }

每次触底时,页码+1,都去请求一次这个方法,并将数据push进去,然后再触发computedShowData方法,计算出实际显示的数据有哪些,可视区域盒子 距离 全部内容盒子 的高度

// 计算显示数据及显示盒子距顶部距离
    computedShowData() {
      this.allBoxHeight = this.allDataArr.length * this.itemHeight; // 计算全部内容盒子的高度(所有数据条数*每条数据盒子card组件的高)
      let {
        queryData: { page, pagenum },
        showLen,
        currentPage
      } = this;
      if (currentPage < showLen) {
        this.top = 0;
        this.forEachArr = this.allDataArr.slice(0, showLen * pagenum);
      } else {
        // 加一是为了将显示内容区域显示在屏幕中,否则无法触发触底事件
        this.top = (currentPage + 1 - showLen) * pagenum * this.itemHeight;
        this.forEachArr = this.allDataArr.slice(
          (currentPage - 2) * pagenum,
          currentPage * pagenum
        );
      }
      console.log("this.forEachArr", this.forEachArr);
    }

每次向上滚动时怎么计算呢,其实是在之前提到的滚动事件中处理的。每次滚动时,去计算出当前的滚动条是处于哪个page的,处于哪一页,我们就取出相对应的数据显示在可视区域中

// 滚动条
    onScroll(val) {
      let currentHeight = val.target.scrollTop + this.systemHeight;
      // 计算每一页数据的高度
      let onePageHeight = this.itemHeight * this.queryData.pagenum;
      // 现在显示的数据的页数
      if (currentHeight < onePageHeight) {
        this.currentPage = 1;
      } else {
        this.currentPage = Math.ceil(currentHeight / onePageHeight);
      }
      console.log(
        "currentPage",
        this.currentPage,
        currentHeight,
        onePageHeight
      );
    },

监听每次滚动时页码page如果有变化就触发之前的计算事件computedShowData

watch: {
    currentPage(newVal, oldVal) {
      console.log("newVal, oldVal", newVal, oldVal);
      if (newVal < oldVal) {
        this.computedShowData();
      } else {
        if (newVal <= this.queryData.page) {
          this.computedShowData();
        }
      }
    }
  }

好了,大概思路就是这样,有需要demo的点这里。全部代码:

index.vue

<template>
  <scroll-view
    scroll-y
    class="main-box"
    :style="{height:systemHeight+'px'}"
    @scrolltolower="handleToBottom"
    @scroll="onScroll"
    lower-threshold="300rpx"
  >
    <!-- 全部内容盒子高度 -->
    <div class="scroll-box" :style="{height:allBoxHeight+'px'}">
      <!-- 可视区域盒子 -->
      <div class="scroll-main" :style="{top:top+'px'}">
        <card v-for="(item,i) in forEachArr" :key="i" :text="item" />
      </div>
    </div>
  </scroll-view>
</template>

<script>
import card from "@/components/card";
export default {
  data() {
    return {
      forEachArr: [], // 显示数据
      allDataArr: [], // 全部数据
      allBoxHeight: 0, // 全部内容盒子高度
      top: 0, // 可视区域盒子距离顶部距离
      queryData: {
        platform: "ZPo4MV4TqsLfAHkist6wQai7S8tzDVmz",
        page: 1,
        pagenum: 10 // 每页条数
      },
      showLen: 3, // 显示数据页数
      currentPage: 1, // 当前滑动到的页数
      itemHeight: 200, // 以各手机屏幕最低高度
      systemHeight: 0, // 设备屏幕高度
      isdisabaled: false
    };
  },

  watch: {
    currentPage(newVal, oldVal) {
      console.log("newVal, oldVal", newVal, oldVal);
      if (newVal < oldVal) {
        this.computedShowData();
      } else {
        if (newVal <= this.queryData.page) {
          this.computedShowData();
        }
      }
    }
  },

  methods: {
    // 请求数据
    queryList() {
      if (!this.isdisabaled) {
        wx.showLoading({ title: "加载中..." });
        this.isdisabaled = true;
        wx.request({
          url: "https://w.taopaitang.com/api/discover",
          method: "GET",
          data: this.queryData,
          header: {
            "content-type": "application/json" // 默认值
          },
          dataType: "json",
          success: res => {
            wx.hideLoading();
            if (res.data.code !== 200) {
              wx.showToast({
                title: res.data.message,
                icon: "none",
                duration: 2000,
                mask: true
              });
            } else {
              let data = res.data.data.items;
              if (this.queryData.page === 1) {
                this.allDataArr = data;
              } else {
                this.allDataArr = this.allDataArr.concat(data);
              }
              this.computedShowData();
              this.isdisabaled = false;
            }
          }
        });
      }
    },
    // 触底 ***必须异步
    async handleToBottom() {
      this.queryData.page += 1;
      await this.queryList();
    },
    // 滚动条
    onScroll(val) {
      let currentHeight = val.target.scrollTop + this.systemHeight;
      // 计算每一页数据的高度
      let onePageHeight = this.itemHeight * this.queryData.pagenum;
      // 现在显示的数据的页数
      if (currentHeight < onePageHeight) {
        this.currentPage = 1;
      } else {
        this.currentPage = Math.ceil(currentHeight / onePageHeight);
      }
      console.log(
        "currentPage",
        this.currentPage,
        currentHeight,
        onePageHeight
      );
    },
    // 计算显示数据及显示盒子距顶部距离
    computedShowData() {
      this.allBoxHeight = this.allDataArr.length * this.itemHeight;
      let {
        queryData: { page, pagenum },
        showLen,
        currentPage
      } = this;
      if (currentPage < showLen) {
        this.top = 0;
        this.forEachArr = this.allDataArr.slice(0, showLen * pagenum);
      } else {
        // 加一是为了将显示内容区域显示在屏幕中,否则无法触发触底事件
        this.top = (currentPage + 1 - showLen) * pagenum * this.itemHeight;
        this.forEachArr = this.allDataArr.slice(
          (currentPage - 2) * pagenum,
          currentPage * pagenum
        );
      }
      console.log("this.forEachArr", this.forEachArr);
    }
  },

  onLoad() {
    this.queryList();// 请求数据
    wx.getSystemInfo({
      success: res => {
        this.systemHeight = res.windowHeight;
      }
    });
  },

  components: {
    card
  }
};
</script>

<style scoped>
.main-box .scroll-box {
  position: relative;
  width: 100%;
}
.main-box .scroll-box .scroll-main {
  position: absolute;
  left: 0;
  width: 100%;
}
</style>

card.vue

<template>
  <div>
    <div class="card">
      <p>{{text.desc}}</p>
      <img :src="text.imgUrl" />
    </div>
  </div>
</template>

<script>
export default {
  props: ["text"]
};
</script>

<style>
.card {
  display: flex;
  padding: 20rpx;
  text-align: center;
  /* height: 570rpx; */
}
.card img {
  width: 640rpx;
  height: 480rpx;
}
</style>


GitHub 地址 demo

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值