关于微信小程序:微信小程序瀑布流和虚拟列表

119次阅读

共计 4028 个字符,预计需要花费 11 分钟才能阅读完成。

微信小程序瀑布流和虚构列表

尽管本篇是写的微信小程序的案例,然而也可用于 H5,思路是想通的,只是有些 api 的差别,最初会贴代码片段

虚构列表

  • 个别在做长列表优化时,特地是面试时,虚构列表就是个高频词。这个名词听起来很高级,其实原理很简略
  • 虚构列表就是将须要渲染的数组数据革新成二维数组,而后通过监听 DOM 节点在适合的中央切换为占位元素,达到长列表有限滚动时缩小 DOM 渲染的优化
  • JS

    /**
     * 解决占位元素,就是在获取新的数据后
     * 通过 SelectQuery 获取以后数据的理论高度,而后把这个高度设置到占位元素上
     */
    getCurrentItemHeight() {const query = this.createSelectorQuery();
      const {virtualId} = this.data
      query.select(`#${virtualId}`).boundingClientRect()
      query.exec((res) => {
        this.setData({height: res[0].height
        }, this.observePage())
      })
    }
    
    /**
     * 监听元素与页面的相交
     * 能够抉择指定元素为参照区域,也能够抉择页面为参照元素,只是 API 不同
     * @doc https://developers.weixin.qq.com/miniprogram/dev/api/wxml/IntersectionObserver.html
     */
    observePage() {const { virtualId, observeDistance, wrapId} = this.data
      let IntersectionObserver = wx.createIntersectionObserver(this);
      (wrapId ? IntersectionObserver.relativeTo(`#${wrapId}`) : IntersectionObserver.relativeToViewport({top: observeDistance, bottom: observeDistance}))
      .observe(`#${virtualId}`, ({intersectionRatio}) => {
        this.setData({isShow: intersectionRatio > 0,})
      })
    }
  • WXML

    <view id="{{virtualId}}">
      <block wx:if="{{isShow}}">
        <slot></slot>
      </block>
      <view wx:else style="height: {{height}}px"></view>
    </view>

瀑布流

  • 瀑布流,又称瀑布流式布局。视觉体现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会一直加载数据块并附加至以后尾部
  • 瀑布流有多种写法,有通过纯 CSS 实现的,也有借助 JS 实现的,办法很多,然而我为了接下来能与虚构列表相结合,就采纳 JS 的写法,就是通过列数把每一列分为一个独自的子元素,而后会记录每一列的高度,通过判断哪一列高度最小,而后将数据 push 到高度最小的那一列

    /**
     * 获取列表数据
     * @describe 瀑布流解决,哪列高度小,就往哪列 push 新数据
     */
    getList() {let { listQuery: { pageIndex, pageSize}, columns, columnsHeight } = this.data;
        for (let i = 0; i < pageSize; i++) {const height = Math.floor(Math.random() * 100)
            const item = {height: height < 150 ? height + 150 : height,};
            const position = this.computePosition(columnsHeight)
            columns[position].push(item)
            columnsHeight += item.height
        }
        // 在 html 中双重遍历 columns,而后通过 flex:1 均匀分布
        this.setData({columns,})
        this.data.columnsHeight = columnsHeight
    }
    
    /**
     * 获取高度最小列下标
     */
    computePosition(heights) {const min = Math.min(...heights);
    return heights.findIndex((item) => item === min)
    }

瀑布流联合虚构列表

  • 让瀑布流有虚构滚动的能力,思路很简略,就是计算每列的偏移量,因为瀑布流被咱们分成了二维数组,所以每块子元素之间就会因为列高度的不统一产生空白区域,所以须要计算这个空白区域的大小,而后通过 margin-top 挪动列元素达到视觉上的瀑布流连接成果
getList() {let { listQuery: { pageIndex}, column, columnsHeights } = this.data;
  const columns = [];
  // 上一组的高度数据,用于计算偏移值
  const lastHeights = [...columnsHeights];
  // 获取数据
  const list = this.getListData();
  // 初始化以后屏数据
  for (let i = 0; i < column; i++) {columns.push([]);
  }
  // 遍历新数据,调配至各列
  for (let i = 0; i < list.length; i++) {const position = this.computePosition(columnsHeights);
    columns[position].push(list[i]);
    columnsHeights[position] += Number(list[i].height);
  }
  this.setData({[`listData[${pageIndex}]`]: {
      columns,
      columnOffset: this.computeOffset(lastHeights),
    }
  });
  this.data.listQuery.pageIndex = pageIndex + 1;
  this.data.columnsHeights = columnsHeights;
},

/**
 * 获取列表数据
 */
getListData() {const result = []
  for (let i = 0; i < this.data.listQuery.pageSize; i++) {const height = Math.floor(Math.random() * 300);
    const item = {
      height: height < 150 ? height + 150 : height,
      color: this.randomRgbColor(),};
    result.push(item);
  }
  return result;
},

/**
 * 随机生成 RGB 色彩
 */
randomRgbColor() {var r = Math.floor(Math.random() * 256); // 随机生成 256 以内 r 值
  var g = Math.floor(Math.random() * 256); // 随机生成 256 以内 g 值
  var b = Math.floor(Math.random() * 256); // 随机生成 256 以内 b 值
  return `rgb(${r},${g},${b})`; // 返回 rgb(r,g,b)格局色彩
},

/**
 * 获取最小高度列下标
 */
computePosition(heights) {const min = Math.min(...heights);
  return heights.findIndex((item) => item === min);
},

/**
 * 计算偏移量
 */
computeOffset(heights) {const max = Math.max(...heights);
  return heights.map((item) => max - item);
},

onScrollLower() {this.getList();
}
  • WXML

    <view>
    <scroll-view class="virtualScrollView" eventhandle scroll-y bindscrolltolower="onScrollLower">
      <block wx:for="{{listData}}" wx:key="screenIndex" wx:for-index="screenIndex" wx:for-item="screenItem">
        <VirtualItem virtualId="virtual_{{screenIndex}}">
          <view class="virtualScreen">
            <block wx:for="{{screenItem.columns}}" wx:key="columnIndex" wx:for-index="columnIndex" wx:for-item="column" >
              <view style="margin-top: -{{screenItem.columnOffset[columnIndex]}}px;" class="virtualColumn">
                <view wx:for="{{column}}" style="height: {{item.height}}px; background-color: {{item.color}};" wx:key="index" wx:for-item="item" wx:for-index="index">
                  screen: {{screenIndex}}, column: {{columnIndex}}
                </view>
              </view>
            </block>
          </view>
        </VirtualItem>
      </block>
    </scroll-view>
    </view>

总结

  • 代码片段:https://developers.weixin.qq….

正文完
 0