• 微信小程序的无限瀑布流写法


    微信小程序的无限瀑布流实现总算做完了,换了好几种方法,过程中出现了各种BUG。

    首先官方有瀑布流的插件(Skyline /grid-view),不是原生的我就不想引入,因为我的方块流页面已经搭好了,引入说不定就要涉及样式的修改、代码量的增大等麻烦问题。

    H5我虽然也做了瀑布流,但是是用绝对定位来做的,性能消耗有点大。所以小程序这边就是想把原本flex固定宽高的改成两列。(纯CSS就不要想了,根本不可能实现,虽然也查到了新的css瀑布流规则,但绝大部分浏览器不支持也是白搭。)

    方案一:

    1. const query = wx.createSelectorQuery().in(this);
    2. query.select(`.desc-${index}`).boundingClientRect((res) => {
    3. }).exec();

    原本显示的数据先做隐藏,之后利用boundingClientRect来获取隐藏块的高度,再计算对比高度看应该放入list1还是list2中。

    这样做会出现两个问题,第一,新增列会明显抖动,因为image我用了mode="widthFix",加载页面跳一下还好,无限瀑布流是要一直可以下拉加载的,就会导致每次新图出来都要跳一下,体验很差……

    即使第一个问题我可以缓存高度,替换为aspectFill解决。但第二个问题是,它加载越多,异步延迟就越大,会导致后面的高度根本获取不到而无法正常排版(大概超过80条左右?)……

    方案二:

    使用wx.getImageInfo来代替获取图片高度,但这样会出现一个明显的问题,就是每次图片的请求是翻倍的,图片本身就加载请求了一次,现在还多用接口请求了一次,这样做太消耗性能了……

    另外要注意的是,我的文字其实也是不定高度的,所以不能只对比图片,还得把图片以外的因素都加进来才行。

    方案三:

    隐藏块使用bindload获取图片高度。这样既避免了方案一中后续获取不到高度,又使得图片不需要二次请求。于是顺着这个思路走,最终解决了这个浪费了我整整一天工作日的瀑布流问题。

    index.wxml

    1. <template name="card">
    2. <navigator class="recommend-card" url="/pages/trade/detail/index?id={{item.id}}">
    3. <view class="recommend-top">
    4. <image wx:if="{{item.height}}"
    5. class="recommend-img"
    6. src="{{ item.pic }}"
    7. mode="aspectFill"
    8. style="height: {{item.height}}rpx;" />
    9. <image wx:else
    10. class="recommend-img"
    11. src="{{ item.pic }}"
    12. data-index="{{index}}"
    13. bindload="imgLoad"
    14. data-title="{{item.title}}"
    15. mode="widthFix" />
    16. view>
    17. <view class="aui-padded-10 recommend-bottom">
    18. <view class="aui-font-size-14 recommend-title">{{item.title}}view>
    19. <view class="aui-font-size-12 c9 recommend-position">
    20. <image alt="地点" class="position-img" src="{{locUrl}}/svg/trade-position.svg" />
    21. <view class="no-wrap">{{item.province}} {{item.city}}view>
    22. view>
    23. view>
    24. navigator>
    25. template>
    26. <view class="recommend-list">
    27. <template is="card" wx:for="{{tradeList}}" wx:key="index" data="{{item, locUrl, index}}">template>
    28. view>
    29. <view class="flex-b">
    30. <view>
    31. <template is="card" wx:for="{{list1}}" wx:key="index" data="{{item, locUrl, index}}">template>
    32. view>
    33. <view>
    34. <template is="card" wx:for="{{list2}}" wx:key="index" data="{{item, locUrl, index}}">template>
    35. view>
    36. view>

    index.js

    1. import { dealTradePic } from "~/utils/trade";
    2. Component({
    3. options: {
    4. addGlobalClass: true,
    5. },
    6. properties: {
    7. goodsList: {
    8. type: Array,
    9. value: [],
    10. observer(goodsList) {
    11. const tradeList = dealTradePic(goodsList);
    12. const obj = { tradeList };
    13. if (tradeList.length === 10) {
    14. // 因为没有置0处理,重新加载时前10条不会触发onload
    15. const { list1, list2, bufferH1, bufferH2 } = this.data;
    16. obj.list1 = list1.slice(0, 10);
    17. obj.list2 = list2.slice(0, 10);
    18. obj.h1 = bufferH1;
    19. obj.h2 = bufferH2;
    20. }
    21. this.setData(obj);
    22. },
    23. }
    24. },
    25. data: {
    26. locUrl: getApp().locUrl,
    27. tradeList: [],
    28. h1: 0,
    29. h2: 0,
    30. bufferH1: 0,
    31. bufferH2: 0,
    32. list1: [],
    33. list2: [],
    34. count: 0,
    35. },
    36. methods: {
    37. imgLoad(e) {
    38. const { width, height } = e.detail;
    39. const { index, title } = e.currentTarget.dataset;
    40. const { tradeList, list1, list2, h1, h2 } = this.data;
    41. // 高度比例切换
    42. let h = 340 * height / width;
    43. h = h > 480 ? 480 : h;
    44. tradeList[index].height = h;
    45. // 增加文字与其他高度
    46. const word = title.replace(/[^\x00-\xff]/g, "aa").length;
    47. const wh = parseFloat((h + (word > 22 ? 38 : 0)).toFixed(2)) + 150;
    48. if (h1 <= h2) {
    49. list1.push(tradeList[index]);
    50. this.data.h1 = parseFloat(h1.toFixed(2)) + wh;
    51. } else {
    52. list2.push(tradeList[index]);
    53. this.data.h2 = parseFloat(h2.toFixed(2)) + wh;
    54. }
    55. // 初始高度记录,用于清空
    56. this.data.count++;
    57. if (this.data.count === 10) {
    58. this.data.bufferH1 = this.data.h1;
    59. this.data.bufferH2 = this.data.h2;
    60. }
    61. this.setData({ list1, list2 });
    62. }
    63. }
    64. });

    index.wxss

    1. .recommend-list {
    2. display: flex;
    3. flex-flow: row wrap;
    4. justify-content: space-between;
    5. padding: 0;
    6. height: 0;
    7. overflow: hidden;
    8. }
    9. .recommend-card {
    10. box-sizing: border-box;
    11. font-size: 24rpx;
    12. border-bottom: none;
    13. width: 342rpx;
    14. margin-bottom: var(--gap);
    15. }
    16. .recommend-top {
    17. width: 340rpx;
    18. }
    19. .recommend-img {
    20. display: block;
    21. width: 100%;
    22. height: 100%;
    23. border-radius: 16rpx 16rpx 0 0;
    24. overflow: hidden;
    25. }
    26. .recommend-title {
    27. font-size: 28rpx;
    28. overflow: hidden;
    29. -o-text-overflow: ellipsis;
    30. text-overflow: ellipsis;
    31. display: -webkit-box;
    32. -webkit-line-clamp: 2;
    33. -webkit-box-orient: vertical;
    34. }
    35. .recommend-position {
    36. display: flex;
    37. align-items: center;
    38. margin-top: 12rpx;
    39. }
    40. .recommend-bottom {
    41. background-color: white;
    42. border-radius: 0 0 16rpx 16rpx;
    43. }

  • 相关阅读:
    尚硅谷nginx学习笔记
    lintcode 3605 · 二维网格偏移 【数组相关,模拟即可】
    信息系统安全运维模型 课堂记录
    构建api gateway之 openresty 中如何使用 wasm
    STL库:list
    ElementUI之动态树+数据表格+分页
    【ASP.NET Core】自己编程来生成自签名的服务器证书
    大语言模型RAG-技术概览 (一)
    MybatisPlus自设模板:填补原模板在controller层对CURD操作的缺乏
    webpack plugin
  • 原文地址:https://blog.csdn.net/guozhicaice/article/details/133267876