最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

antd?3.x?Table組件如何快速實(shí)現(xiàn)虛擬列表詳析

 更新時(shí)間:2022年11月29日 09:36:08   作者:Yue櫟廷  
這篇文章主要給大家介紹了關(guān)于antd?3.x?Table組件如何快速實(shí)現(xiàn)虛擬列表的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用antd具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

1. 前言

隨著互聯(lián)網(wǎng)的發(fā)展,web展示的內(nèi)容越來(lái)越豐富,也越來(lái)越無(wú)窮。我們?cè)趯?shí)際開(kāi)發(fā)中難免會(huì)遇到長(zhǎng)列表數(shù)據(jù)渲染,而又不適合分頁(yè)的業(yè)務(wù)場(chǎng)景,如果瀏覽器直接渲染海量數(shù)據(jù),會(huì)造成頁(yè)面卡死,嚴(yán)重時(shí)導(dǎo)致瀏覽器資源耗盡,直接崩潰掉。這種情況用戶與產(chǎn)品是無(wú)法接受的,瀏覽器性能與業(yè)務(wù)需求產(chǎn)生了對(duì)立,因此虛擬列表技術(shù)被提出,為這種尷尬的場(chǎng)面提供了一線生機(jī)。

2. 虛擬列表

虛擬列表其實(shí)是按需顯示的一種實(shí)現(xiàn),即只對(duì)可見(jiàn)區(qū)域進(jìn)行渲染,對(duì)非可見(jiàn)區(qū)域中的數(shù)據(jù)不渲染或部分渲染的技術(shù),從而達(dá)到極高的渲染性能。假設(shè)有10萬(wàn)條記錄需要同時(shí)渲染,我們屏幕的可見(jiàn)區(qū)域的高度為500px,而列表項(xiàng)的高度為50px,則此時(shí)我們?cè)谄聊恢凶疃嘀荒芸吹?0個(gè)列表項(xiàng),那么在渲染的時(shí)候,我們只需加載可視區(qū)的那10條即可,觸發(fā)頁(yè)面滾動(dòng)時(shí),實(shí)時(shí)替換當(dāng)前應(yīng)該展示在頁(yè)面中的10條數(shù)據(jù)。

它的名詞解釋由一張圖來(lái)詮釋,如下:

觸發(fā)滾動(dòng)后,可視區(qū)域內(nèi)的數(shù)據(jù)變化:

  • 首先,定義一個(gè)visibleHeight變量來(lái)保存我們可見(jiàn)區(qū)域的高度,作為內(nèi)容容器,并設(shè)置為500px,visibleHeight = 500
  • 假設(shè)每列高度itemHeight固定,則可見(jiàn)區(qū)域內(nèi)的數(shù)據(jù)條數(shù)visibleCount = Math.ceil(visibleHeight / itemHeight)
  • 由于只渲染可視區(qū)域內(nèi)的數(shù)據(jù),所以我們需要另一個(gè)占位容器,使父盒子出現(xiàn)滾動(dòng)條,占位容器高度placeholderHeight = totalCount * itemHeight。占位容器替代了內(nèi)容容器,撐出了滾動(dòng)條,內(nèi)容盒子則采用絕對(duì)定位脫離文檔流。
  • 每當(dāng)觸發(fā)滾動(dòng)時(shí),獲取滾動(dòng)條的滾動(dòng)距離,計(jì)算出應(yīng)該總共滾動(dòng)了的數(shù)據(jù)條數(shù),從而設(shè)置數(shù)據(jù)的開(kāi)始索引startIdx = Math.floor(scrollTop / itemHeight),而結(jié)束索引endIdx = startIdx + visibleCount。
  • 如果是原生開(kāi)發(fā),則根據(jù)開(kāi)始、結(jié)束索引去操作dom,替換dom。如果是vue或react都是數(shù)據(jù)驅(qū)動(dòng),則更新要渲染的list數(shù)據(jù)即可,renderList = sourceList.slice(startIdx, endIdx)
  • 最后一點(diǎn),我們的可視數(shù)據(jù)列表需要根據(jù)每次滾動(dòng)的距離相應(yīng)地調(diào)整內(nèi)容容器的位置,以保證在父盒子的滾動(dòng)下,內(nèi)容容器始終在可視區(qū)域中,offset = startIdx * itemCount,offset則為內(nèi)容容器相對(duì)于占位容器的偏移距離。

首先,準(zhǔn)備dom結(jié)構(gòu):

<div className="wrapper" style={{
    position: "relative",
    overflow: "auto"
}}>
    <div className="placeholder-list" style={{ 
        height: `${visibleHeight}px` 
    }}></div>
    <div className="render-list" style={{ 
        postion: "absolute", 
        top: 0, 
        left: 0
    }}>...</div>
</div>

wrapper添加滾動(dòng)事件實(shí)現(xiàn)邏輯:

scrollEvent(e){
    const startIdx = Math.floor(e.target.scrollTop / itemHeight);
    const endIdx = startIdx + visibleCount;
    setList(source.slice(startIdx, endIdx));
    // 設(shè)置偏移距離,保持?jǐn)?shù)據(jù)在視圖中
    const offset = startIdx * itemHeight;
    listRef.current.style.top = offset + "px";
}

我們發(fā)現(xiàn),快速滾動(dòng)時(shí)最下方會(huì)出現(xiàn)空白的現(xiàn)象,因?yàn)榇藭r(shí)數(shù)據(jù)還沒(méi)渲染成功。為了優(yōu)化此空白,考慮多渲染2條數(shù)據(jù)作為緩沖區(qū)。因此visibelCount=Math.ceil(visibelHeight / itemHeight) + 2

代碼完整示例:

import { useCallback, useEffect, useRef, useState } from "react";

const visibleHeight = 360;
const itemHeight = 50;
const visibleCount = Math.ceil(visibleHeight / itemHeight) + 2;
const totalCount = 100;

const source = Array.from(Array(totalCount), (item, index) => index);

export default function VirtualList() {
  const [list, setList] = useState(source);
  const listRef = useRef();

  const scrollEvent = useCallback((e) => {
    const startIdx = Math.floor(e.target.scrollTop / itemHeight);
    const endIdx = startIdx + visibleCount;
    setList(source.slice(startIdx, endIdx));
    const offset = startIdx * itemHeight;
    listRef.current.style.top = offset + "px";
  }, []);
  
  useEffect(() => {
    listRef.current = document.querySelector(".list");
  }, []);
  
  return (
    <div
      style={{
        backgroundColor: "#FFF",
        height: visibleHeight + 'px',
        textAlign: "center",
        overflow: "auto",
        position: "relative",
        overscrollBehavior: 'contain'
      }}
      onScroll={scrollEvent}
    >
      <div style={{ height: totalCount * itemHeight + 'px' }}></div>
      <div
        className="list"
        style={{
          position: "absolute",
          top: 0,
          left: 0,
          width: "100%",
          height: visibleHeight + 'px'
        }}
      >
        {list.map((item) => {
          return (
            <div
              key={item}
              style={{ height: itemHeight + 'px', borderBottom: "1px solid #eee" }}
            >
              {item}
            </div>
          );
        })}
      </div>
    </div>
  );
}

3. 虛擬table

終于來(lái)到了標(biāo)題的內(nèi)容,如何對(duì)antd table3.x進(jìn)行虛擬表格的封裝。其實(shí)和上述的代碼差不多,只不過(guò)對(duì)于有的新手同學(xué)來(lái)講,可能有點(diǎn)摸不著入口,所以有了本節(jié)內(nèi)容。

目前在antd4.x版本table已經(jīng)實(shí)現(xiàn)了開(kāi)啟虛擬列表的配置,拿來(lái)即用。針對(duì)3.x的版本自己實(shí)現(xiàn)了一個(gè)虛擬table,解決了業(yè)務(wù)上長(zhǎng)列表渲染卡頓的問(wèn)題。

注意:Table每項(xiàng)需要定高,因此columns屬性中需要ellipsis:true保證數(shù)據(jù)只展示一行,溢出展示省略號(hào)。

根據(jù)上節(jié)內(nèi)容介紹的虛擬列表思路,我們需要準(zhǔn)備2個(gè)容器,一個(gè)內(nèi)容容器,Table已經(jīng)提供了,另一個(gè)占位容器沒(méi)有提供,所以需要手動(dòng)創(chuàng)建一個(gè)并放在合適的地方。通過(guò)開(kāi)發(fā)者工具審查元素找到Table內(nèi)提供的那個(gè)內(nèi)容容器.ant-table-body table,獲取其dom。父容器.ant-table-body,創(chuàng)建一個(gè)占位容器div,追加到父容器內(nèi)。通過(guò)元素審查也知道Table tr高度為54px,即itemHeight=54

知道了類名,就可以獲取到Table的dom為所欲為了。

useEffect(() => {
    const parentNode = document.querySelector('.ant-table-body');
    const table = document.querySelector('.ant-table-body table');
    // 用ref保持table方便在滾動(dòng)事件中使用table dom
    tableRef.current = table;
    // 創(chuàng)建一個(gè)占位的div,高度等于所有數(shù)據(jù)高度,用來(lái)?yè)伍_(kāi)容器展示滾動(dòng)條
    const placeholderWrapper = document.createElement('div');
    placeholderWrapper.style.height = itemHeight * totalCount + 'px'
    parentNode.appendChild(placeholderWrapper);
    // 子絕父相口訣,為table設(shè)置定位,脫離文檔流,把位置讓給占位盒子
    parentNode.style.position = 'relative';
    table.style.position = 'absolute';
    table.style.top = 0;
    table.style.left = 0;
    // 添加滾動(dòng)事件
    parentNode.addEventListener('scroll', scrollEvent)
    return () => {
      // 清理占位盒子
      parentNode.removeChild(placeholderWrapper);
      parentNode.removeEventListener('scroll', scrollEvent)
    }
  }, [scrollEvent]);

接下來(lái)實(shí)現(xiàn)滾動(dòng)事件,和上節(jié)內(nèi)容一致,保存范圍索引到state中:

const scrollEvent = useCallback((e) => {
    const startIdx = Math.floor(e.target.scrollTop / itemHeight);
    const endIdx = startIdx + visibleCount;
    // 保存當(dāng)前的范圍索引,用來(lái)slice源數(shù)據(jù)給展示用
    setRange([startIdx, endIdx]);
    const offset = startIdx * itemHeight;
    tableRef.current.style.top = offset + "px";
  }, []);

根據(jù)范圍索引,截取當(dāng)前要展示的數(shù)據(jù)項(xiàng)

const [range, setRange] = useState([]);
// 這個(gè)renderList就是需要給Table組件的
const renderList = useMemo(() => {
    const [start, end] = range;
    return dataSource.slice(start, end)
  }, [range])

return <Table dataSource={renderList} />

全文示例代碼Github地址。

4.總結(jié)

本文只是實(shí)現(xiàn)了在固定每項(xiàng)列表高度的情況下的虛擬列表,現(xiàn)實(shí)很多情況是不定高的。這個(gè)比定高的復(fù)雜,不過(guò)原理也是一樣的,多了一步需要計(jì)算渲染后的實(shí)際高度的步驟。后續(xù)會(huì)完善不定高的虛擬列表的實(shí)現(xiàn)。

本文的內(nèi)容也是我在工作中遇到的情況,應(yīng)該很多其他小伙伴也會(huì)遇到antd 3.x table的虛擬化的問(wèn)題,希望能給小伙伴們一點(diǎn)思路。因此有了本文,也是自己一次關(guān)于輸入與輸出的記錄與沉淀。

到此這篇關(guān)于antd 3.x Table組件如何快速實(shí)現(xiàn)虛擬列表的文章就介紹到這了,更多相關(guān)antd 3.x Table組件虛擬列表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • ReactNative之鍵盤(pán)Keyboard的彈出與消失示例

    ReactNative之鍵盤(pán)Keyboard的彈出與消失示例

    本篇文章主要介紹了ReactNative之鍵盤(pán)Keyboard的彈出與消失示例,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-07-07
  • React key值的作用和使用詳解

    React key值的作用和使用詳解

    這篇文章主要介紹了React key值的作用和使用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • react使用axios實(shí)現(xiàn)上傳下載功能

    react使用axios實(shí)現(xiàn)上傳下載功能

    這篇文章主要為大家詳細(xì)介紹了react使用axios實(shí)現(xiàn)上傳下載功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • React Native中NavigatorIOS組件的簡(jiǎn)單使用詳解

    React Native中NavigatorIOS組件的簡(jiǎn)單使用詳解

    這篇文章主要介紹了React Native中NavigatorIOS組件的簡(jiǎn)單使用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • React應(yīng)用框架Dva數(shù)據(jù)流向原理總結(jié)分析

    React應(yīng)用框架Dva數(shù)據(jù)流向原理總結(jié)分析

    這篇文章主要為大家介紹了React 應(yīng)用框架Dva數(shù)據(jù)流向原理總結(jié)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • React反向代理及樣式獨(dú)立詳解

    React反向代理及樣式獨(dú)立詳解

    這篇文章主要介紹了React反向代理及樣式獨(dú)立詳解,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-08-08
  • GraphQL在react中的應(yīng)用示例詳解

    GraphQL在react中的應(yīng)用示例詳解

    這篇文章主要為大家介紹了GraphQL在react中的應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • react實(shí)現(xiàn)動(dòng)態(tài)增減表單項(xiàng)的示例代碼

    react實(shí)現(xiàn)動(dòng)態(tài)增減表單項(xiàng)的示例代碼

    在做項(xiàng)目的時(shí)候,甲方給的信息有限,網(wǎng)頁(yè)的備案信息寫(xiě)成固定的,之后驗(yàn)收的時(shí)候,甲方要求把這個(gè)備案信息寫(xiě)成動(dòng)態(tài)的,可以自增減,下面通過(guò)實(shí)例代碼給大家介紹react實(shí)現(xiàn)動(dòng)態(tài)增減表單項(xiàng)的示例,感興趣的朋友跟隨小編一起看看吧
    2024-05-05
  • react 生命周期實(shí)例分析

    react 生命周期實(shí)例分析

    這篇文章主要介紹了react 生命周期,結(jié)合實(shí)例形式分析了react 生命周期基本原理、操作步驟與注意事項(xiàng),需要的朋友可以參考下
    2020-05-05
  • React組件三大屬性之state,props,refs

    React組件三大屬性之state,props,refs

    這篇文章主要介紹了React組件三大屬性之state,props,refs,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-07-07

最新評(píng)論

铜川市| 灵璧县| 连山| 梁平县| 甘德县| 五寨县| 云林县| 襄樊市| 阿拉尔市| 石渠县| 宜州市| 白河县| 花垣县| 平原县| 宁化县| 盐城市| 博野县| 石嘴山市| 双城市| 磐安县| 平度市| 荥经县| 增城市| 汤阴县| 平阴县| 杭锦后旗| 花莲县| 库尔勒市| 客服| 石家庄市| 桦甸市| 曲阳县| 白河县| 乐昌市| 固镇县| 黄浦区| 德令哈市| 华坪县| 广州市| 海城市| 民丰县|