mpvue微信小程序长列表

末蓝、 2023-06-19 06:47 29阅读 0赞

mpvue微信小程序长列表

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

github demo地址

  1. <scroll-view
  2. scroll-y
  3. class="main-box"
  4. :style="{height:systemHeight+'px'}"
  5. @scrolltolower="handleToBottom"
  6. @scroll="onScroll"
  7. lower-threshold="300rpx"
  8. >
  9. <!-- 全部内容盒子高度 -->
  10. <div class="scroll-box" :style="{height:allBoxHeight+'px'}">
  11. <!-- 可视区域盒子 -->
  12. <div class="scroll-main" :style="{top:top+'px'}">
  13. <card v-for="(item,i) in forEachArr" :key="i" :text="item" />
  14. </div>
  15. </div>
  16. </scroll-view>

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

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

  1. onLoad() {
  2. this.queryList();// 请求数据
  3. wx.getSystemInfo({
  4. success: res => {
  5. this.systemHeight = res.windowHeight;
  6. }
  7. });
  8. }

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

  1. // 请求数据
  2. queryList() {
  3. if (!this.isdisabaled) {
  4. wx.showLoading({ title: "加载中..." });
  5. this.isdisabaled = true;
  6. wx.request({
  7. url: "https://w.taopaitang.com/api/discover",
  8. method: "GET",
  9. data: this.queryData,
  10. header: {
  11. "content-type": "application/json" // 默认值
  12. },
  13. dataType: "json",
  14. success: res => {
  15. wx.hideLoading();
  16. if (res.data.code !== 200) {
  17. wx.showToast({
  18. title: res.data.message,
  19. icon: "none",
  20. duration: 2000,
  21. mask: true
  22. });
  23. } else {
  24. let data = res.data.data.items;
  25. if (this.queryData.page === 1) {
  26. this.allDataArr = data;
  27. } else {
  28. this.allDataArr = this.allDataArr.concat(data);
  29. }
  30. this.computedShowData();
  31. this.isdisabaled = false;
  32. }
  33. }
  34. });
  35. }
  36. }

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

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

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

  1. // 滚动条
  2. onScroll(val) {
  3. let currentHeight = val.target.scrollTop + this.systemHeight;
  4. // 计算每一页数据的高度
  5. let onePageHeight = this.itemHeight * this.queryData.pagenum;
  6. // 现在显示的数据的页数
  7. if (currentHeight < onePageHeight) {
  8. this.currentPage = 1;
  9. } else {
  10. this.currentPage = Math.ceil(currentHeight / onePageHeight);
  11. }
  12. console.log(
  13. "currentPage",
  14. this.currentPage,
  15. currentHeight,
  16. onePageHeight
  17. );
  18. },

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

  1. watch: {
  2. currentPage(newVal, oldVal) {
  3. console.log("newVal, oldVal", newVal, oldVal);
  4. if (newVal < oldVal) {
  5. this.computedShowData();
  6. } else {
  7. if (newVal <= this.queryData.page) {
  8. this.computedShowData();
  9. }
  10. }
  11. }
  12. }

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

index.vue

  1. <template>
  2. <scroll-view
  3. scroll-y
  4. class="main-box"
  5. :style="{height:systemHeight+'px'}"
  6. @scrolltolower="handleToBottom"
  7. @scroll="onScroll"
  8. lower-threshold="300rpx"
  9. >
  10. <!-- 全部内容盒子高度 -->
  11. <div class="scroll-box" :style="{height:allBoxHeight+'px'}">
  12. <!-- 可视区域盒子 -->
  13. <div class="scroll-main" :style="{top:top+'px'}">
  14. <card v-for="(item,i) in forEachArr" :key="i" :text="item" />
  15. </div>
  16. </div>
  17. </scroll-view>
  18. </template>
  19. <script>
  20. import card from "@/components/card";
  21. export default {
  22. data() {
  23. return {
  24. forEachArr: [], // 显示数据
  25. allDataArr: [], // 全部数据
  26. allBoxHeight: 0, // 全部内容盒子高度
  27. top: 0, // 可视区域盒子距离顶部距离
  28. queryData: {
  29. platform: "ZPo4MV4TqsLfAHkist6wQai7S8tzDVmz",
  30. page: 1,
  31. pagenum: 10 // 每页条数
  32. },
  33. showLen: 3, // 显示数据页数
  34. currentPage: 1, // 当前滑动到的页数
  35. itemHeight: 200, // 以各手机屏幕最低高度
  36. systemHeight: 0, // 设备屏幕高度
  37. isdisabaled: false
  38. };
  39. },
  40. watch: {
  41. currentPage(newVal, oldVal) {
  42. console.log("newVal, oldVal", newVal, oldVal);
  43. if (newVal < oldVal) {
  44. this.computedShowData();
  45. } else {
  46. if (newVal <= this.queryData.page) {
  47. this.computedShowData();
  48. }
  49. }
  50. }
  51. },
  52. methods: {
  53. // 请求数据
  54. queryList() {
  55. if (!this.isdisabaled) {
  56. wx.showLoading({ title: "加载中..." });
  57. this.isdisabaled = true;
  58. wx.request({
  59. url: "https://w.taopaitang.com/api/discover",
  60. method: "GET",
  61. data: this.queryData,
  62. header: {
  63. "content-type": "application/json" // 默认值
  64. },
  65. dataType: "json",
  66. success: res => {
  67. wx.hideLoading();
  68. if (res.data.code !== 200) {
  69. wx.showToast({
  70. title: res.data.message,
  71. icon: "none",
  72. duration: 2000,
  73. mask: true
  74. });
  75. } else {
  76. let data = res.data.data.items;
  77. if (this.queryData.page === 1) {
  78. this.allDataArr = data;
  79. } else {
  80. this.allDataArr = this.allDataArr.concat(data);
  81. }
  82. this.computedShowData();
  83. this.isdisabaled = false;
  84. }
  85. }
  86. });
  87. }
  88. },
  89. // 触底 ***必须异步
  90. async handleToBottom() {
  91. this.queryData.page += 1;
  92. await this.queryList();
  93. },
  94. // 滚动条
  95. onScroll(val) {
  96. let currentHeight = val.target.scrollTop + this.systemHeight;
  97. // 计算每一页数据的高度
  98. let onePageHeight = this.itemHeight * this.queryData.pagenum;
  99. // 现在显示的数据的页数
  100. if (currentHeight < onePageHeight) {
  101. this.currentPage = 1;
  102. } else {
  103. this.currentPage = Math.ceil(currentHeight / onePageHeight);
  104. }
  105. console.log(
  106. "currentPage",
  107. this.currentPage,
  108. currentHeight,
  109. onePageHeight
  110. );
  111. },
  112. // 计算显示数据及显示盒子距顶部距离
  113. computedShowData() {
  114. this.allBoxHeight = this.allDataArr.length * this.itemHeight;
  115. let {
  116. queryData: { page, pagenum },
  117. showLen,
  118. currentPage
  119. } = this;
  120. if (currentPage < showLen) {
  121. this.top = 0;
  122. this.forEachArr = this.allDataArr.slice(0, showLen * pagenum);
  123. } else {
  124. // 加一是为了将显示内容区域显示在屏幕中,否则无法触发触底事件
  125. this.top = (currentPage + 1 - showLen) * pagenum * this.itemHeight;
  126. this.forEachArr = this.allDataArr.slice(
  127. (currentPage - 2) * pagenum,
  128. currentPage * pagenum
  129. );
  130. }
  131. console.log("this.forEachArr", this.forEachArr);
  132. }
  133. },
  134. onLoad() {
  135. this.queryList();// 请求数据
  136. wx.getSystemInfo({
  137. success: res => {
  138. this.systemHeight = res.windowHeight;
  139. }
  140. });
  141. },
  142. components: {
  143. card
  144. }
  145. };
  146. </script>
  147. <style scoped>
  148. .main-box .scroll-box {
  149. position: relative;
  150. width: 100%;
  151. }
  152. .main-box .scroll-box .scroll-main {
  153. position: absolute;
  154. left: 0;
  155. width: 100%;
  156. }
  157. </style>

card.vue

  1. <template>
  2. <div>
  3. <div class="card">
  4. <p>{
  5. {text.desc}}</p>
  6. <img :src="text.imgUrl" />
  7. </div>
  8. </div>
  9. </template>
  10. <script>
  11. export default {
  12. props: ["text"]
  13. };
  14. </script>
  15. <style>
  16. .card {
  17. display: flex;
  18. padding: 20rpx;
  19. text-align: center;
  20. /* height: 570rpx; */
  21. }
  22. .card img {
  23. width: 640rpx;
  24. height: 480rpx;
  25. }
  26. </style>

GitHub 地址 demo

发表评论

表情:
评论列表 (有 0 条评论,29人围观)

还没有评论,来说两句吧...

相关阅读