精品欧美一区二区三区在线观看 _久久久久国色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综合中文字幕| 国产免费人做人爱午夜视频| 欧美一区二区三区| 成人黄色在线看| 国产精品高精视频免费| 成人免费看片98| 欧美一二区在线观看| 精品久久免费看| 五月婷婷深爱五月| av中文字幕在线看| 日韩一区欧美小说| 欧美日韩精品免费观看| 精品久久久久中文慕人妻| 麻豆久久精品| 久久久久久中文字幕| 国产91在线播放九色| 天堂在线精品| 精品国产乱码久久久久久浪潮 | 日本蜜桃在线观看| 成人av电影在线| 91在线视频精品| 中文字幕精品一区二| 99视频一区| 久久91精品国产91久久跳| 国产又黄又粗的视频| 激情小说亚洲图片| 欧美一级免费观看| av免费一区二区| 日韩免费小视频| 精品毛片网大全| 国产曰肥老太婆无遮挡| 中文字幕在线三区| 中文字幕一区二区日韩精品绯色| 欧美一二三四五区| 奇米影视888狠狠狠777不卡| 99在线热播精品免费| 国产传媒一区二区| www.日日夜夜| 国产成人免费在线视频| 亚洲va欧美va国产综合久久| 一级全黄少妇性色生活片| 日本亚洲免费观看| 日本电影亚洲天堂| 亚洲 欧美 中文字幕| 亚洲一区一卡| 日本久久中文字幕| 亚洲s码欧洲m码国产av| 鲁大师成人一区二区三区| 欧洲成人免费视频| www亚洲视频| 久久久久久穴| 国产精品video| 国产第一页在线观看| 日韩一区精品视频| 国产精品女视频| 一区不卡在线观看| 国产在线精品一区二区| 51国偷自产一区二区三区| 美国黑人一级大黄| 欧美一区二区三区在线免费观看| 成人午夜精品福利免费| 成人国产精品免费网站| 国外成人在线视频网站| 91青草视频久久| 亚洲欧美日韩激情| 青青草97国产精品免费观看| 国产精品在线看| 国产绿帽刺激高潮对白| 国产传媒欧美日韩成人| 国产手机精品在线| 久久久pmvav| 欧美激情中文字幕一区二区| 亚洲巨乳在线观看| 精品176二区| 一区二区三区四区av| 日本十八禁视频无遮挡| 久久久人成影片一区二区三区在哪下载 | 国产一级淫片久久久片a级| 日韩情爱电影在线观看| 久久av在线看| 国产视频91在线| 青青草成人在线观看| 91手机在线播放| 手机看片福利在线观看| 国产精品第一页第二页第三页| 免费日韩在线观看| 制服丝袜专区在线| 7777精品伊人久久久大香线蕉| 美女伦理水蜜桃4| 综合国产视频| 久久成人18免费网站| 欧美三级一区二区三区| 蜜臀av国产精品久久久久| 成人国产一区二区| 亚洲AV成人无码一二三区在线| 99视频在线精品| 亚洲一区三区视频在线观看| 岛国片av在线| 欧美日韩视频在线一区二区| 少妇熟女视频一区二区三区| 激情小说亚洲色图| 亚洲摸下面视频| 岛国毛片在线观看| 日韩有码一区二区三区| 国产伦精品一区二区三区| 69av亚洲| 欧美视频在线观看免费| 韩国三级丰满少妇高潮| 精品国产一级毛片| 午夜精品久久久久久99热| 国产又粗又长视频| 久久久久久久久伊人| 黄色一级片在线看| 国产成人免费视频网站视频社区 | 在线一区二区三区四区五区 | 91精品国产91久久久久久吃药| 一区二区国产欧美| 国产亚洲综合色| 久草免费福利在线| 国产精品国产亚洲精品| 亚洲天堂av在线免费观看| 黄网站免费在线| 精品无码三级在线观看视频 | 第三区美女视频在线| 欧美日韩国产色视频| 中文字幕在线视频一区二区| 色琪琪久久se色| 国产成人精品免费视频| 婷婷久久久久久| 亚洲午夜激情网站| 师生出轨h灌满了1v1| 国产精品毛片久久| 国产日韩欧美在线观看| avav免费在线观看| 欧美午夜宅男影院| 亚洲一区二区三区蜜桃| 国产亚洲精品bv在线观看| 国产精品一区二区免费| 国产丝袜在线观看视频| 日韩午夜激情免费电影| 欧美成人一二三区| 国产精品中文字幕日韩精品| 欧美aaa在线观看| 欧美高清免费| www日韩欧美| 国产精品毛片一区视频播| 国产精品日韩成人| 日韩欧美亚洲另类| 欧美.www| 国产精品二区在线| 成人在线免费观看黄色| 精品剧情v国产在线观看在线| 久久久久黄色片| 国产91露脸合集magnet| 轻点好疼好大好爽视频| 久久夜色电影| 日韩av免费网站| yw193.com尤物在线| 欧美日韩综合不卡| 国产又粗又硬又长又爽| 国产一区二区按摩在线观看| 国产一二三四五| 成人三级毛片| 欧美亚洲日本网站| 成人免费高清在线播放| 欧美日韩一二三| 国产高潮国产高潮久久久91| 粉嫩aⅴ一区二区三区四区| 欧美日韩精品在线一区二区| 国产探花一区在线观看| 国产精品色婷婷视频| 好吊日视频在线观看| 精品国产电影一区二区| 欧美videossex极品| 国产三级一区二区三区| 色婷婷一区二区三区av免费看| 在线成人激情| 国产一区二区无遮挡| 久久xxx视频| 欧美成年人视频网站欧美| 农村少妇久久久久久久| 日韩欧美在线视频免费观看| 91动漫免费网站| 国产成人欧美日韩在线电影| 国产综合免费视频| 亚洲国产老妈| 免费观看成人在线| 亚洲国产一区二区久久| 久久露脸国产精品| 99r精品视频| 国内精品在线播放| 一区二区三区四区免费视频| 久久gogo国模啪啪裸体| 欧美亚洲国产视频小说| 欧美激情免费| 精品福利一区二区三区| 这里只有精品999| 亚洲精品乱码久久久久久久久| 自拍视频一区二区| 国产一区二区网址| 少妇人妻在线视频| 欧美mv日韩| 美乳视频一区二区| 日韩欧美中文字幕一区二区三区| **欧美日韩vr在线| a视频在线观看免费| 亚洲欧美制服另类日韩| 亚洲成人av综合| 欧美日韩日本视频| 国产又大又黄视频| 亚洲精品午夜久久久| 国产黄色大片免费看| 成人精品国产福利| 成年人性生活视频| 免播放器亚洲一区| 黄色片视频在线免费观看| 午夜国产精品视频免费体验区| 欧洲精品国产| 国产精品久久久久久久久久白浆| 国产裸体写真av一区二区| 性欧美超级视频| 91精品国产色综合久久不卡98口 | 一级黄色免费片| 色哟哟一区二区三区| 日本中文字幕网| 一区二区三区四区精品在线视频| 午夜国产福利视频| 久久久91精品国产一区二区精品 | 三上悠亚av一区二区三区| 亚洲在线视频| aa在线观看视频| 亚洲性人人天天夜夜摸| 国产片侵犯亲女视频播放| 欧美成人一品| 久久免费视频2| 91日韩视频| 超碰免费在线公开| 国产精品毛片久久| 蜜桃视频成人在线观看| 久久中文字幕av一区二区不卡| 日韩av一区二区三区美女毛片| 米奇精品关键词| 久久精彩视频| 亚洲+变态+欧美+另类+精品| 亚洲欧洲色图| 91久久精品一区二区三| 久久久综合久久| 一区二区三区四区亚洲| 免费一级黄色大片| 一区二区三区中文字幕精品精品| 日韩精品一区二区亚洲av性色| 一色屋精品亚洲香蕉网站| 日韩一区二区三区四区视频| 欧美激情资源网| 中国美女黄色一级片| 中文字幕在线观看不卡| 欧美h片在线观看| 亚洲欧美日本韩国| 免费看一级一片| 亚洲a一区二区| 手机看片久久久| 欧美午夜影院一区| 国产精品久久久午夜夜伦鲁鲁| 在线播放中文一区| www.黄色片| 亚洲护士老师的毛茸茸最新章节| 三级av在线播放| 色偷偷av一区二区三区乱| 黄色网址在线免费| 久久不见久久见免费视频7| 国产午夜精品全部视频播放| www.成人.com| 精品国产欧美成人夜夜嗨| 最新超碰在线| 欧美亚洲在线播放| 成人在线免费av| 99国精产品一二二线| 天堂俺去俺来也www久久婷婷| 日韩精品电影网站| 中文字幕一区二区三三| 成人毛片视频网站| 日韩av中文字幕一区二区| 男女污污视频网站| 99精品国产热久久91蜜凸| 久久久久久国产免费a片| 成人免费在线视频观看| 日韩无码精品一区二区三区| 欧洲av在线精品| www.日日夜夜| 国产一区二区三区18| 青春草免费在线视频| 日韩av免费在线观看| 国色天香久久精品国产一区| 久久av一区二区| 希岛爱理一区二区三区| 大肉大捧一进一出好爽动态图| 国内精品不卡在线| 四虎永久免费影院| 伊人开心综合网| 国产美女www爽爽爽| 精品国产乱码久久久久久免费| 欧美成年黄网站色视频| 77777亚洲午夜久久多人| 日本精品久久| 欧美专区一二三| 最新国产乱人伦偷精品免费网站| 国产美女18xxxx免费视频| 久久天堂av综合合色蜜桃网| www青青草原| 欧美三级一区二区| 在线观看xxx| 欧美激情手机在线视频| 大胆国模一区二区三区| 丝袜美腿玉足3d专区一区| 99精品国产在热久久| 久久久久久国产精品日本| 欧美高清在线一区| 久久久成人免费视频| 日韩精品亚洲精品| 丰满的护士2在线观看高清| 亚洲专区中文字幕| 色中色综合网| 日韩一级片播放| 久久亚洲私人国产精品va媚药| 久久无码精品丰满人妻| 91精品国产综合久久久久久久久久 | 超碰97久久国产精品牛牛| 一级日韩一区在线观看| 鲁大师成人一区二区三区| 日韩aaaaa| 亚洲福利电影网| www.色婷婷.com| 欧美激情视频一区| 亚洲成av人片在线观看www| 在线免费观看成人网| 美女视频网站久久| 国产一区二区三区视频播放| 精品视频999| 日本视频在线播放| 国产日韩精品在线播放| 青青草综合网| 国产九九在线观看| 国产精品国模大尺度视频| 伊人精品一区二区三区| 中文字幕一区二区精品| 福利精品一区| 伊人久久青草| 国产精品夜夜嗨| 久久久久97国产| 亚洲激情视频在线观看| 国产夫妻在线| 蜜桃久久精品乱码一区二区 | 国产一级免费片| 亚洲va在线va天堂| 无码国产精品一区二区免费16| 91精品国产免费久久久久久| 免费看av成人| 性欧美videossex精品| 国产精品福利电影一区二区三区四区| 97超碰人人草| 欧美日韩xxx| 婷婷综合福利| 亚洲三级视频网站| 亚洲欧美在线视频观看| 蜜桃久久一区二区三区| 亚洲2020天天堂在线观看| 国产传媒欧美日韩成人精品大片| 中文字幕欧美人妻精品一区| 国产精品久久久久久一区二区三区| 国产伦精品一区二区三区免.费| 欧美精品在线播放| 日韩极品在线| 男操女免费网站| 亚洲精品国产无天堂网2021| 天堂在线视频免费观看| 日本中文字幕久久看| 亚洲欧美日韩高清在线| 艳妇乳肉豪妇荡乳xxx| 欧美在线制服丝袜| av官网在线播放| 欧美日韩亚洲一区二区三区在线观看| 蜜桃免费网站一区二区三区| 欧美久久久久久久久久久久| 日韩高清人体午夜| 亚洲高清影院| 日本三级免费观看| 亚洲色图欧美偷拍| 婷婷五月综合激情| 成人黄色在线播放| 国产一区导航| 国产一二三四区| 亚洲性猛交xxxxwww| 欧州一区二区三区| 久久午夜夜伦鲁鲁一区二区| 草草视频在线观看|