如何解決快應用頁面滑動卡頓問題

華為開發者論壇發表於2021-08-16

問題現象

頁面一次載入了 100 條資料,頁面滑動出現卡頓。

問題程式碼

<template>
  <div class="container">
    <div class="nav">
      <text class="nav-item">list</text>
    </div>
 
    <!-- List -->
    <list class="list" onclick="listClick" onlongpress="listLongPress"
      onscrollbottom="scrollbottom"  id="list" scrollpage="{{scrollPage}}">
 
      <list-item type="listItem" class="item"  onclick="listItemClick"
        if="{{listData.length>0}}">
           <div for="{{listData}}" style="flex-direction:column;">
                <text  class="txt">{{$item}}--{{$idx}}</text>
           </div>
      </list-item>
 
      <!-- Loading More  -->
      <list-item type="loadMore" class="load-more" if="{{loadMore}}">
        <progress type="circular"></progress>
        <text>More</text>
      </list-item>
    </list>
 
  </div>
</template>
<style>
 
  .container{
     flex-direction: column;
  }
 
  .list {
    padding-left: 10px;
    padding-right: 10px;
    columns: 1;
    flex-direction: column;
    border-color: #FF0000;
    border-width: 5px;
  }
 
  .item {
    flex-direction: column;
    align-items: flex-start;
    margin-bottom: 15px;
    border-color: #9400D3;
    border-width: 5px;
    margin-right: 20px;
    background-color: #f76160;
  }
 
  .load-more {
    justify-content: center;
    align-items: center;
    height: 100px;
    border-color: #bbbbbb;
    border-bottom-width: 1px;
  }
 
  .btn-little {
    flex: 1;
    height: 80px;
    margin-left: 15px;
    border-radius: 5px;
    color: #ffffff;
    font-size: 30px;
    text-align: center;
    background-color: #0faeff;
  }
 
  .nav {
    padding-left: 60px;
    padding-right: 60px;
    padding-bottom: 30px;
  }
 
  .nav-item {
    flex: 1;
    padding-bottom: 30px;
    border-bottom-width: 5px;
    border-color: #fbf9fe;
    font-size: 35px;
    color: #666666;
    text-align: center;
  }
 
</style>
<script>
  import prompt from '@system.prompt'
 
  export default {
    data: {
      componentName: 'list',
      loadMore: true,
      listAdd: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],
      listData: [],
      scrollPage: false,
    },
    onInit: function () {
      this.$page.setTitleBar({ text: 'list' })
      for(var index = 0;index < 100;index++){
          this.listData[index] = 'A';
     }
      
    },
  
    scrollbottom: function () {
      prompt.showToast({
        message: 'The list slides to the bottom and starts loading other data.'
      })
      // Load next page
      var that = this
      var renderData = [].concat(that.listData, that.listAdd)
      setTimeout(function () {
        that.listData = renderData
      }, 1000)
    },
 
    // monitoring during sliding
    scroll: function (e) {
      let msg = 'scroll' + '.scrollX:' + e.scrollX
        + ' .scrollY:' + e.scrollY
        + ' .scrollState:' + e.scrollState
      console.info(msg)
    },
  
  
    listItemClick: function (e) {
      e.stopPropagation()
      console.info('List Item is clicked.')
      prompt.showToast({
        message: 'List Item is clicked.'
      })
    },
    listClick: function (e) {
      e.stopPropagation()
      console.info('List is clicked.')
      prompt.showToast({
        message: 'List is clicked.'
      })
    },
 
    listLongPress: function (e) {
      e.stopPropagation()
      console.info('List is long pressed.')
      prompt.showToast({
        message: 'List is long pressed.'
      })
    },
  }
</script>

問題分析

      以上程式碼使用list list-item 來載入大規模資料,但是使用方法不當,導致list-item 的檢視view 沒有被複用。

我們知道快應用的引擎是一個android apk list list-item 的實現最終都是透過android ListView BaseAdapter 等這些實現的,瞭解這些其實知道列表介面上超過螢幕顯示的區域是不會重新建立檢視的,而是複用第一次在介面上可見區域的那些view 的,只需要把資料重新整理一下即可。每一行的檢視view 其實就是list-item

以上程式碼雖然看起來是列表,但是隻有1 list-item ,開發者在list-item 內部使用了for 迴圈,每迴圈一次,都會建立一個新的view ,當資料量很大時,記憶體佔用越多,手機記憶體吃緊,不斷地做申請、釋放記憶體的操作,應用效能受到嚴重影響,導致滑動卡頓。

解決方法

    基於list 元件的特點,在list-item 內部內部需謹慎使用if 指令或for 指令,根據列表每行資料特點,在list-item 上設定不同的type ,儘可能複用list-item ,在list-item 上使用for 語句。修改後程式碼如下( 注意list-item部分):

<template>
  <div class="container">
    <div class="nav">
      <text class="nav-item">list</text>
    </div>
 
    <!-- List -->
    <list class="list" onclick="listClick" onlongpress="listLongPress"
      onscrollbottom="scrollbottom"  id="list" scrollpage="{{scrollPage}}">
     
      <list-item type="listItem" class="item item-color"  onclick="listItemClick"
        for="{{listData}}">
        <text  class="txt">{{$item}}--{{$idx}}</text>
      </list-item>
 
      <!-- <list-item type="listItem" class="item"  onclick="listItemClick"
        if="{{listData.length>0}}">
           <div for="{{listData}}" style="flex-direction:column;">
                <text  class="txt">{{$item}}--{{$idx}}</text>
           </div>
      </list-item> -->
 
      <!-- Loading More  -->
      <list-item type="loadMore" class="load-more" if="{{loadMore}}">
        <progress type="circular"></progress>
        <text>More</text>
      </list-item>
    </list>
 
  </div>
</template>

程式碼執行效果圖對比:              

     1 修改後效果

2  修改前效果


從上面效果圖中我們看到,雖然都是列表資料,但是圖1 每一行都是一個list-item list-item css 中背景色設定的是紅色),而且type 值都一樣,能很好地複用list-item ,但是圖2 中只有1 list-item ,裡面列表資料都是作為list-item 的子節點。圖2 的效果和使用普通的div 載入大量列表資料是一樣的,根源在於開發者沒有很好地理解list list-item 的原理。

 

欲瞭解更多詳情,請參見:

快應用list 開發指導:

https://developer.huawei.com/consumer/cn/doc/development/quickApp-References/quickapp-component-list#h1-1592485335262

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69970551/viewspace-2787085/,如需轉載,請註明出處,否則將追究法律責任。

相關文章