精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從原理到實踐:如何在Taro中構建高效且易用的虛擬列表

開發 前端
在通過scrollToIndex找到該節點即將渲染在第幾頁,在這之前的幾頁都需要我們手動執行以下監聽每一屏是否在可視區,因為在這之后的頁都會通過觸底這一操作來執行監聽。

前言

最近在小程序的工作中有許多場景是大數據量的列表渲染,這種渲染場景如果不對它進行優化會非常耗性能,常見的優化手段有:分片渲染與虛擬列表,恰好Taro官方也有提供虛擬列表組件,但有同事反饋這個組件并不好用,體驗也不好,白屏非常明顯。

在虛擬列表中滾動過快造成的白屏其實是必然的,關鍵在于我們怎么去優化它,把白屏比例盡量降到最低,這其中還得權衡性能與體驗,想要白屏越少,那么你要渲染的節點就越多,性能自然也就越差。反之,你想要性能好,那么白屏就會增加。

接下來,自己動手實現一個虛擬列表,支持以下功能:

  • 元素定高,可支持滾動到指定元素位置
  • 元素不定高,無需關心子元素的高度,組件內自動計算
  • 可支持一次性加載所有數據,也支持分頁加載數據

原理介紹

虛擬列表的原理其實就是:只渲染可視區內的元素,對于非可視區的元素不進行渲染,這樣就可以提高長列表的渲染性能。

但是為了在滾動過程盡可能的降低白屏率,我們可以多渲染幾屏元素

圖片圖片

如上圖,原理大概是這樣:

  • 將數據處理成每一屏一個渲染單位,用二維數組存儲
  • 使用Taro.createIntersectionObserver監聽每一屏內容是否在可視區,在可視區直接渲染,不在可視區則使用該屏真實高度進行占位。高度怎么來?可以定高,也可以不定高,不定高的話就是等每一屏渲染完成后記錄渲染高度即可,兩種都有實現,具體可以看下面的實現方法

這樣的話,每次真實渲染的節點數就遠小于列表全部渲染的節點數,可以極大地提高頁面渲染性能。

實現

處理數據

首先將外部的數據處理成二維數組,方便后續按屏渲染

// 處理列表數據,按規則分割
let initList: any[] = []; // 初始列表(備用)
const dealList = (list: any[]) => {
  const segmentNum = props?.segmentNum; // 每頁顯示數量
  let arr: any[] = [];
  const _list: any[] = [];
  list.forEach((item, index) => {
    arr.push(item);
    if ((index + 1) % segmentNum === 0) {
      _list.push(arr);
      arr = [];
    }
  });
  // 處理余數
  const restList = list.slice(_list.length * segmentNum);
  if (restList.length) {
    _list.push(restList);
  }
  initList = _list;
};

計算渲染高度

在處理完數據后,接著我們就是取出每一屏的數據進行渲染,接著計算并存儲渲染后每一屏所占用的高度,在后續滾動過程中,如果該屏內容離開可視區,我們就可以將該屏的內容替換成對應高度進行渲染占位,這樣就可以減少真實渲染的節點數。

// 計算每一頁數據渲染完成后所占的高度
const setheight = (list: any[], pageIndex?: number) => {
  const index = pageIndex ?? renderPageIndex.value;
  const query = Taro.createSelectorQuery();

  query.select(`.inner_list_${index}`).boundingClientRect();
  query.exec((res) => {
    if (list?.length) {
      pageHeightArr.value.push(res?.[0]?.height);  // 存儲每一屏真實渲染高度
    }
  });
  observePageHeight(pageIndex); // 監聽頁面高度
};

監聽每一屏是否在可視區

上面提到的當每一屏的內容離開可視區就需要將該屏內容替換為占位高度,這個功能的實現就需要借助Taro.createIntersectionObserver這個API來完成。

這里需要注意的是relativeToViewport可以自定義監視區域,如果想要滾動過程減少白屏概率,那么可以將監視區域擴大,但渲染性能也會隨之變差,所有這里可以按自己的業務需要考量

const observePageHeight = (pageIndex?: number) => {
  const index = pageIndex ?? renderPageIndex.value;
  observer = Taro.createIntersectionObserver(
    currentPage.page as any,
  ).relativeToViewport({
    top: props?.screenNum * pageHeight,
    bottom: props?.screenNum * pageHeight,
  });
  console.log('observer', observer);
  // console.log("index", `.inner_list_${index}`);
  observer?.observe(`.inner_list_${index}`, (res) => {
    console.log(`.inner_list_${index}`, res.intersectionRatio);
    if (res.intersectionRatio <= 0) {
      // 當沒有交集時,說明當前頁面已經不在視口內,則將該屏數據修改為該屏高度進行占位
      towList.value[index] = {
        height: pageHeightArr.value[index],
      };
    } else {
      // 當有交集時,說明當前頁面在視口內
      if (!towList.value[index]?.length) {
        towList.value[index] = initList[index];
      }
    }
  });
};

觸底監聽

UI層,使用了scrollView組件來渲染列表,真實列表項渲染提供插槽給外部自行處理

<scroll-view
      v-if="list?.length"
      class="list"
      :scrollY="true"
      :showScrollbar="false"
      :lowerThreshold="lowerThreshold"
      :scrollTop="scrollTop"
      @scrollToLower="renderNext"
      :enhanced="true"
      :bounces="false"
      :enablePassive="true"
      :style="{ height: height }"
    >
      <view
        :class="[`inner_list_${pageIndex}`]"
        :id="`inner_list_${pageIndex}`"
        v-for="(page, pageIndex) in towList"
        :key="pageIndex"
      >
        <template v-if="page?.length > 0">
          <view
            :id="`item_${pageIndex}_${index}`"
            v-for="(item, index) in page"
            :key="index"
          >
            <slot v-if="item" name="listItem" :item="item"></slot>
          </view>
        </template>
        <view v-else :style="{ height: `${pageHeightArr[pageIndex]}px` }">
        </view>
      </view>
      <!-- 底部自定義內容 -->
      <slot name="renderBottom"></slot>
    </scroll-view>

通過lowerThreshold監聽觸底操作,將二維數組每一項取出來渲染,當每一頁的內容都渲染完后,那么頁面最終的所有節點將會是:真實列表內容 + 占位高度,后續只需要依賴上一步驟的監聽就可以完成真實內容渲染與占位高度之間的切換。

// 渲染下一頁
const renderNext = () => {
  // if (!towList.value[pageIndex]?.length) {
  //   // 無數據
  // }
    renderPageIndex.value += 1; // 更新當前頁索引
    if (renderPageIndex.value >= initList.length) {
      // 已經到底
      return;
    }
    towList.value[renderPageIndex.value] = initList[renderPageIndex.value];

    Taro.nextTick(() => {
      setheight(props?.list);
    });
};

這樣基本就完成一個虛擬列表組件,我們來看看效果:

// 渲染數據
const list = ref(
  new Array(10000).fill(0).map((_, i) => {
    return {
      label: `第 ${i} 章`,
      value: i,
      isLock: false,
      time: "2023-01-12 16:07",
      type: "chapter",
    };
  }),
); // 列表數據

這里模擬了10000條數據來測試:

圖片圖片

初始渲染只有兩頁內容,每一頁渲染20條。

當我們滾動頁面時,就會根據監聽來加入渲染內容,并且將不在可視區的內容替換成占位高度。

圖片圖片

但是我們的業務還需要定位功能,定位到某一章高亮,這里就需要計算滾動高度了,雖然scrollView組件提供了scrollIntoView屬性,可以使列表滾動到對應子元素位置,但是我發現只有它的第一層子元素能夠生效,對于他的孫子元素并不生效。

定高滾動至指定位置

由于我這里是按頁來渲染的,需要定位到的元素并不是它的第一層子元素,所以這個方法在這里并不適用,最終只能計算滾動高度來實現。

const formateList = (list: any[]): void => {
  const scrollToIndex = props?.scrollToIndex; // 滾動到指定位置
  const itemHeight =
    itemRenderHeight.value || (props?.itemHeight ?? 0) * (pageWidth / 375); // 每一項的真實渲染高度
  const segmentNum = props?.segmentNum; // 每頁顯示數量
  dealList(list);
  if (itemHeight && scrollToIndex !== undefined) {
    // 定高,可滾動至指定位置
    // console.log("scrollToIndex", scrollToIndex);
    const startIndex = Math.floor(scrollToIndex / segmentNum); // 找到當前索引所在的頁面
    console.log("startIndex", startIndex);
    renderPageIndex.value = startIndex; // 更新當前頁索引
    const pageHeight = segmentNum * itemHeight; // 一屏的高度
    console.log("pageHeight", pageHeight, itemHeight);
    // readyList
    for (let i = 0; i < startIndex; i++) {
      pageHeightArr.value[i] = pageHeight;
      towList.value[i] = {
        height: pageHeight,
      };
    }
    towList.value[startIndex] = initList[startIndex];
    if (startIndex + 1 < initList.length) {
      towList.value[startIndex + 1] = initList[startIndex + 1];
    }
    Taro.nextTick(() => {
      for (let i = 0; i < startIndex; i++) {
        // observePageHeight(i);
        setheight(list, i);
      }
      scrollTop.value = scrollToIndex * itemHeight;
      console.log("scrollTop---", scrollTop.value);
    });
  } else {
    // console.log("當前為不定高虛擬列表");
    towList.value = initList.slice(0, 1);
    Taro.nextTick(() => {
      setheight(list);
    });
  }
};

通過scrollToIndex計算出需要定位到的位置。

圖片圖片

這里需要注意的是,在通過scrollToIndex找到該節點即將渲染在第幾頁,在這之前的幾頁都需要我們手動執行以下監聽每一屏是否在可視區,因為在這之后的頁都會通過觸底這一操作來執行監聽。如果少了這一步那么之前的這幾頁都會白屏,無真實數據渲染。

責任編輯:武曉燕 來源: 前端南玖
相關推薦

2017-08-10 09:11:38

規則引擎構建

2024-07-07 21:49:22

2025-03-17 01:55:00

TCP服務迭代

2024-03-27 10:14:48

2025-11-11 07:54:21

2025-09-08 07:14:25

2025-09-04 01:33:00

Flowable工作流引擎

2025-08-07 07:36:06

2023-12-13 13:15:13

平臺開發實踐

2021-05-11 07:51:30

React ref 前端

2025-06-30 03:25:00

2025-04-01 01:04:00

Redis集群緩存

2025-05-16 07:24:41

Springkafka腳手架

2010-06-29 14:20:52

2025-10-27 01:22:00

HTTP接口API

2025-06-30 04:15:00

2024-01-19 16:35:23

2023-08-03 08:03:05

2024-12-12 09:00:28

2024-12-17 08:04:04

點贊
收藏

51CTO技術棧公眾號

亚洲综合一二三区| 国产一区二区三区免费播放| 亚洲美女av网站| 天天干天天玩天天操| av电影高清在线观看| 成人a免费在线看| 国产成人精品视频| 中文字幕av久久爽av| 午夜精品福利影院| 911精品产国品一二三产区| av网站大全免费| 成人精品福利| 波多野结衣亚洲一区| 国产精品九九久久久久久久| 久久综合亚洲色hezyo国产| 丝袜连裤袜欧美激情日韩| 欧美男男青年gay1069videost| 成人免费性视频| 成人av毛片| 成人国产视频在线观看| 国产主播在线一区| 天堂中文在线网| 欧美在线二区| 在线观看欧美日韩| 可以直接看的无码av| 电影中文字幕一区二区| 欧美自拍丝袜亚洲| 熟女少妇在线视频播放| 操你啦视频在线| 国产欧美日韩在线| 美女主播视频一区| 亚洲狼人综合网| 精彩视频一区二区三区| 国产999精品久久久| 国产精品第72页| 欧美一区二区三区另类| 中文字幕欧美日韩| 日本少妇高潮喷水xxxxxxx| 国产精品毛片av| 欧美α欧美αv大片| 想看黄色一级片| www.一区| 欧美日韩免费在线视频| 国产性生交xxxxx免费| 欧美私密网站| 精品国产1区2区| 国产 日韩 欧美在线| 日本在线视频中文有码| 亚洲码国产岛国毛片在线| 一区二区三区四区视频在线观看 | 一区二区三区日韩在线| 一级特级黄色片| 久久国产精品色av免费看| 精品日韩av一区二区| 曰本三级日本三级日本三级| 中文字幕综合| 91精选在线观看| 日韩欧美亚洲另类| 性欧美video另类hd尤物| 欧美精品久久一区二区三区| www.色欧美| 电影中文字幕一区二区| 日韩三级在线免费观看| 香蕉网在线视频| 91成人噜噜噜在线播放| 亚洲国产一区二区三区四区| 超碰97在线资源站| 免费成人高清在线视频theav| 日韩精品免费电影| 欧美大波大乳巨大乳| 秋霞欧美视频| 久久亚洲综合国产精品99麻豆精品福利 | 一区二区在线视频观看| 亚洲精品720p| 欧美色图亚洲激情 | 日本黄色播放器| 国产婷婷视频在线| 亚洲一二三区视频在线观看| 久久久亚洲精品无码| 欧美极品影院| 欧美日本在线看| 潘金莲一级淫片aaaaa| 国产精品一区二区中文字幕| 亚洲色图日韩av| 黄色录像免费观看| 99精品国产在热久久| 国产成人拍精品视频午夜网站| 亚洲一级片免费看| 成人精品高清在线| 五月天婷亚洲天综合网鲁鲁鲁| 精品美女在线观看视频在线观看| 亚洲一二三区视频在线观看| 亚洲色精品三区二区一区| 91麻豆精品国产综合久久久| 亚洲国产精品久久久久秋霞蜜臀| 精品人妻无码一区| 综合一区在线| 日本亚洲欧美三级| 99re只有精品| xfplay精品久久| 91九色国产ts另类人妖| 忘忧草在线日韩www影院| 欧美日韩国产成人在线免费| 男人网站在线观看| 97色伦图片97综合影院| 亚洲91精品在线| 国产精品自偷自拍| 国产日韩在线不卡| 欧美黄网在线观看| 欧美日韩精品免费观看视欧美高清免费大片| 91精品国产全国免费观看| 欧美熟妇一区二区| 欧美天天视频| 91久久久久久| 国产在线视频网站| 午夜精品免费在线观看| 91香蕉国产线在线观看| 国产真实有声精品录音| 亚州av一区二区| 亚洲不卡免费视频| 综合欧美一区二区三区| 欧美精品第三页| 成人h动漫免费观看网站| 日韩亚洲精品电影| 午夜精品一区二| 91农村精品一区二区在线| 九一免费在线观看| 亚洲精品tv| 日韩在线观看精品| 中文字幕第31页| 久久免费美女视频| 欧美啪啪免费视频| 国产欧美自拍一区| 欧美精品激情在线| 午夜精品久久久久久久96蜜桃| 亚洲欧洲av色图| 国产97色在线 | 日韩| 亚洲黄页在线观看| 97久久精品在线| 五月婷婷激情在线| 五月天一区二区| 欧美日韩一区二区三区四区五区六区| 91精品啪在线观看国产18| 国产精品专区h在线观看| 国产九九在线| 在线亚洲高清视频| 国产一级久久久久毛片精品| 亚洲男女自偷自拍| 久久综合中文色婷婷| 欧美亚洲日本精品| 亚洲免费视频在线观看| 中文字幕69页| 国产亚洲va综合人人澡精品| 天天天干夜夜夜操| 久久精品国产68国产精品亚洲| 国产精品一久久香蕉国产线看观看| 九色在线免费| 欧美亚洲一区三区| 欧美xxxooo| 国产999精品久久久久久绿帽| 亚洲欧美日韩不卡| 免费看日产一区二区三区| 久久成人综合视频| 六月婷婷中文字幕| 欧美午夜精品久久久久久久| 国产交换配乱淫视频免费| 老司机久久99久久精品播放免费| 日本一区不卡| 色噜噜成人av在线| 欧美激情视频在线| 亚洲日本国产精品| 欧美日韩在线不卡| 久操视频免费在线观看| 91色.com| 免费在线观看污网站| 欧美特黄a级高清免费大片a级| 精品国产乱码久久久久久郑州公司 | 亚洲一级二级在线| 欧美偷拍一区二区三区| 久久超级碰视频| 国产精品久久久久久久久电影网| 男人的天堂久久| 国产精品第二页| 亚洲小说区图片| 亚洲美女视频网站| 国产精品丝袜黑色高跟鞋| 亚洲.国产.中文慕字在线| 久久丫精品忘忧草西安产品| 经典三级在线一区| 欧美a在线视频| 久久精品国产www456c0m| 岛国一区二区三区高清视频| 美女一区网站| 欧美另类高清videos| 免费一级在线观看| 欧美一级电影网站| 日本视频网站在线观看| 亚洲另类色综合网站| 国产免费看av| 成人午夜在线视频| 日本高清一区二区视频| 亚洲一区区二区| 热久久最新网址| 精品久久久久久久久久久aⅴ| 97久久人人超碰caoprom欧美| 日韩在线影院| 久久久亚洲影院你懂的| 色三级在线观看| 亚洲美女自拍视频| 东京干手机福利视频| 欧美日韩在线一区二区| 国产一级精品视频| 亚洲一区二区美女| 国产美女久久久久久| 久久精品亚洲精品国产欧美| 自拍视频第一页| 紧缚奴在线一区二区三区| 国产xxxxx视频| 国产视频欧美| 日韩欧美不卡在线| 一本一道久久综合狠狠老| 五月婷婷综合色| 伊人久久大香线蕉综合网站| 国产日韩一区欧美| 欧美日韩黄色| 91在线|亚洲| 亚洲狼人在线| 国产免费一区视频观看免费| 日韩成人高清| 日本久久久久亚洲中字幕| 999福利在线视频| 欧美极品少妇xxxxⅹ裸体艺术| 黄色网在线播放| 色综久久综合桃花网| melody高清在线观看| 亚洲情综合五月天| 男人av在线| 亚洲天堂网站在线观看视频| 欧美777四色影视在线 | 黄网站在线播放| www.日本久久久久com.| 在线视频二区| 色婷婷**av毛片一区| 成人午夜在线观看视频| 一区二区三区日韩在线| 在线视频婷婷| 久久精品国产96久久久香蕉| 久热国产在线| 欧美成人中文字幕| 四虎影视成人| 97视频免费在线观看| 老司机深夜福利在线观看| 18性欧美xxxⅹ性满足| 天堂资源在线| 国产精品久久久久国产a级| 黄色欧美视频| 3d精品h动漫啪啪一区二区| 超碰97久久| 久久久久久久久久久一区| 婷婷国产精品| 亚洲国产精品日韩| 亚洲精品a级片| 国产freexxxx性播放麻豆| 99riav1国产精品视频| 欧美日韩二三区| 日韩影院在线观看| 中文字幕视频三区| 国产91对白在线观看九色| 星空大象在线观看免费播放| 97精品国产露脸对白| 国产高清一区二区三区四区| 国产精品传媒在线| 国产亚洲精品成人| 色婷婷香蕉在线一区二区| 一二三区在线播放| 亚洲精品一区在线观看| 嫩草研究院在线观看| 久久久www成人免费精品| 狂野欧美性猛交xxxxx视频| 91国内产香蕉| 国产精品天堂蜜av在线播放| αv一区二区三区| 国产一区二区精品福利地址| 99精品一级欧美片免费播放| 今天的高清视频免费播放成人| 国内外成人免费激情视频| 精一区二区三区| 少妇被狂c下部羞羞漫画| 欧美激情一区在线| 久久精品这里只有精品| 91久久一区二区| www.蜜臀av.com| 亚洲天堂男人的天堂| 中文字幕在线播放网址| 日韩免费在线播放| 中文字幕久久精品一区二区| 日韩欧美第二区在线观看| 狠狠噜噜久久| 中文字幕在线综合| 99国产精品久久久久| 日本高清一二三区| 在线中文字幕一区二区| 亚洲第一视频在线| 日韩在线欧美在线| 欧美电影免费观看高清完整| www.久久爱.cn| 久久视频在线| 动漫av免费观看| 99re免费视频精品全部| 欧美成人精品欧美一| 欧美午夜寂寞影院| 男女污视频在线观看| 国内自拍欧美激情| 日韩视频1区| 中文字幕一区二区三区最新| 久久久久久久高潮| jlzzjizz在线播放观看| 亚洲美女淫视频| 91精品中文字幕| 尤物九九久久国产精品的分类| 成人免费图片免费观看| 亚洲综合精品伊人久久| 色999日韩| 四季av一区二区| 久久久久久久久伊人| 成人午夜淫片100集| 亚洲国内高清视频| 91制片在线观看| 91九色偷拍| 欧美一区精品| 爱情岛论坛亚洲自拍| 综合电影一区二区三区 | 精彩视频一区二区| youjizz亚洲女人| 色婷婷综合久色| 天堂av在线播放| 国语自产精品视频在线看抢先版图片| 日韩精品成人| 国产精品视频网站在线观看| 国产高清精品在线| 欧美成欧美va| 精品av久久707| 99riav视频在线观看| 精品国产综合久久| 国产麻豆综合| av网在线播放| 欧美午夜影院一区| 1pondo在线播放免费| 国产欧美精品一区二区三区介绍| 欧美性感美女一区二区| 日本三级黄色网址| 中文字幕一区二区三区色视频| 一级做a爱片性色毛片| 精品国偷自产在线| 日韩精品一区二区三区中文字幕| 成人短视频在线观看免费| 国产不卡高清在线观看视频| 久久精品久久国产| 日韩精品极品在线观看播放免费视频| 亚洲最新无码中文字幕久久| 欧洲精品久久| 激情五月婷婷综合网| 青青草成人免费| 亚洲国产成人av在线| 性欧美1819sex性高清| 亚洲精品日韩精品| 国产精品一二三| 天天操天天干视频| 国产香蕉97碰碰久久人人| 亚洲午夜剧场| 国产av国片精品| 国产清纯在线一区二区www| 国产乱淫a∨片免费观看| 欧美高清在线播放| 妖精视频一区二区三区| 中文字幕成人在线视频| 一区二区三区欧美| 手机亚洲第一页| 国产一区二区丝袜| 亚洲黄页一区| 日韩一级片在线免费观看| 日韩欧美你懂的| 欧美天堂视频| 浴室偷拍美女洗澡456在线| av影院午夜一区| 一区二区三区在线免费观看视频| 欧美高清自拍一区| 欧美精品一区二区三区精品| 97超碰免费在线观看| 日本精品一区二区三区高清| 久草免费在线| 日韩av一级大片| 成人国产亚洲欧美成人综合网 | 亚洲国内在线| av亚洲产国偷v产偷v自拍| 中文字幕 欧美激情| 国语自产精品视频在线看| 99久久.com| 草草影院第一页| 日韩精品一区二区三区视频播放 |