适用场景

简单场景

开发者在页面中实现长列表或者屏幕滚动等效果时,习惯使用div组件做循环遍历

示例如下:

假设开发者要这样的效果:一个结构简单的商品列表

使用 div 组件的代码如下:

  1. <template>
  2. <!-- div实现 -->
  3. <div class="tutorial-page">
  4. <!-- 商品列表 -->
  5. <block for="productList">
  6. <div class="content-item" onclick="route($item.url)">
  7. <image class="img" src="{{$item.img}}"></image>
  8. <div class="text-wrap">
  9. <div class="top-line">
  10. <text class="text-name">{{$item.name}}</text>
  11. <text class="text-price">{{$item.price}}</text>
  12. </div>
  13. <text class="bottom-line">{{$item.brief}}</text>
  14. </div>
  15. </div>
  16. </block>
  17. <!-- 加载更多,监听通用事件appear,出现时加载更多数据 -->
  18. <div class="load-more" onappear="loadMoreData">
  19. <progress type="circular"></progress>
  20. <text>加载更多</text>
  21. </div>
  22. </div>
  23. </template>

然而,当 DOM 结构复杂时,滚动页面会出现卡顿现象,因为 Native 无法复用 div 组件实现的列表元素

为了得到流畅的列表滚动体验,推荐开发者使用list组件替代div组件实现长列表布局,因为 Native 会复用相同type属性list-item

使用 list 组件的代码如下:

<template>
  <!-- 列表实现 -->
  <list class="tutorial-page" onscrollbottom="loadMoreData">
    <!-- 商品列表 -->
    <block for="productList">
      <list-item type="product" class="content-item" onclick="route($item.url)">
        <image class="img" src="{{$item.img}}"></image>
        <div class="text-wrap">
          <div class="top-line">
            <text class="text-name">{{$item.name}}</text>
            <text class="text-price">{{$item.price}}</text>
          </div>
          <text class="bottom-line">{{$item.brief}}</text>
        </div>
      </list-item>
    </block>

    <!-- 加载更多,type属性自定义命名为loadMore -->
    <list-item type="loadMore" class="load-more">
      <progress type="circular"></progress>
      <text>加载更多</text>
    </list-item>
  </list>
</template>

要实现 DOM 片段的复用,要求相同type属性的 DOM 结构完全相同。所以,设置相同type属性list-item是优化列表滚动性能的关键

注意:

  • list-item内不能再嵌套list
  • list-itemtype属性为必填属性
  • list-item内部需谨慎使用if指令for指令,因为相同type属性list-item的 DOM 结构必须完全相同,而使用if指令for指令会造成 DOM 结构差异提示:

若遇到类似xxx cannot be cast to xxx at …list的错误,请检查list-item组件是否存在如下情形:

  • 未设置type属性。解决方案:设置type属性
  • 内部使用了if指令。解决方案:使用show指令代替if指令,或设置不同的type属性
  • 设置为相同的type属性,但 DOM 结构不一致。解决方案:设置不同的type属性

复杂场景

实现简单的商品列表,了解list组件的基本用法和优化性能的关键后,接下来通过实现多种列表元素类型的复杂列表,进一步了解list组件

示例如下:

假设开发者要实现这样的效果:一个商品列表页,图片位于左边和图片位于右边的商品交错显示

列表中的列表元素可以分为三类,设置三种不同type属性list-item。分别为:

  • 图片在左,文字在右的list-itemtype属性自定义命名为productLeft
  • 图片在右,文字在左的list-itemtype属性自定义命名为productRight
  • 加载更多的list-itemtype属性自定义命名为loadMore示例代码如下:
<template>
  <!-- list中可以划分为三种类型的DOM结构,对应三种type属性的list-item -->
  <list class="tutorial-page" onscrollbottom="loadMoreData">
    <block for="{{productList}}">
      <!-- 图片在左,文字在右的list-item,type属性自定义命名为productLeft -->
      <list-item type="productLeft" class="content-item" if="{{$idx%2 === 0}}" onclick="route($item.url)">
        <image class="img" src="{{$item.img}}"></image>
        <div class="text-wrap">
          <div class="top-line">
            <text class="text-name">{{$item.name}}</text>
            <text class="text-price">{{$item.price}}</text>
          </div>
          <text class="bottom-line">{{$item.brief}}</text>
        </div>
      </list-item>

      <!-- 图片在右,文字在左的list-item,type属性自定义命名为productRight -->
      <list-item type="productRight" class="content-item" if="{{$idx%2 === 1}}" onclick="route($item.url)">
        <div class="text-wrap">
          <div class="top-line">
            <text class="text-name">{{$item.name}}</text>
            <text class="text-price">{{$item.price}}</text>
          </div>
          <text class="bottom-line">{{$item.brief}}</text>
        </div>
        <image class="img" src="{{$item.img}}"></image>
      </list-item>
    </block>

    <!-- 加载更多的list-item,type属性自定义命名为loadMore -->
    <list-item type="loadMore" class="load-more">
      <progress type="circular"></progress>
      <text>加载更多</text>
    </list-item>
  </list>
</template>