成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

淺說虛擬列表的實(shí)現(xiàn)原理

趙春朋 / 1464人閱讀

摘要:虛擬列表的實(shí)現(xiàn)有多種方案,本文以組件為基礎(chǔ)進(jìn)行分析。常見的無限滾動(dòng)便是延遲渲染的一種實(shí)現(xiàn),而虛擬列表則是按需渲染的一種實(shí)現(xiàn)。接下來,本文會(huì)簡單介紹虛擬列表的一種實(shí)現(xiàn)方案。實(shí)現(xiàn)本章節(jié)將會(huì)創(chuàng)建一個(gè)組件,并結(jié)合代碼,慢慢梳理虛擬列表的實(shí)現(xiàn)。

在 列表數(shù)據(jù)的展示優(yōu)化 一文中,提到了對(duì)于列表形態(tài)的數(shù)據(jù)展示的按需渲染。這種方式是指根據(jù)容器元素的高度以及列表項(xiàng)元素的高度來顯示長列表數(shù)據(jù)中的某一個(gè)部分,而不是去完整地渲染長列表,以提高無限滾動(dòng)的性能。而按需顯示方案的實(shí)現(xiàn)就是本文標(biāo)題中說的虛擬列表。

虛擬列表的實(shí)現(xiàn)有多種方案,本文以 react-virtual-list 組件為基礎(chǔ)進(jìn)行分析。原文鏈接:https://github.com/dwqs/blog/...
什么是虛擬列表?

在正文之前,先對(duì)虛擬列表做個(gè)簡單的定義。

根據(jù)上文,虛擬列表是按需顯示思路的一種實(shí)現(xiàn),即虛擬列表是一種根據(jù)滾動(dòng)容器元素的可視區(qū)域來渲染長列表數(shù)據(jù)中某一個(gè)部分?jǐn)?shù)據(jù)的技術(shù)。

簡而言之,虛擬列表指的就是「可視區(qū)域渲染」的列表。有三個(gè)概念需要了解一下:

滾動(dòng)容器元素:一般情況下,滾動(dòng)容器元素是 window 對(duì)象。然而,我們可以通過布局的方式,在某個(gè)頁面中任意指定一個(gè)或者多個(gè)滾動(dòng)容器元素。只要某個(gè)元素能在內(nèi)部產(chǎn)生橫向或者縱向的滾動(dòng),那這個(gè)元素就是滾動(dòng)容器元素考慮每個(gè)列表項(xiàng)只是渲染一些純文本。在本文中,只討論元素的縱向滾動(dòng)。

可滾動(dòng)區(qū)域:滾動(dòng)容器元素的內(nèi)部內(nèi)容區(qū)域。假設(shè)有 100 條數(shù)據(jù),每個(gè)列表項(xiàng)的高度是 50,那么可滾動(dòng)的區(qū)域的高度就是 100 * 50。可滾動(dòng)區(qū)域當(dāng)前的具體高度值一般可以通過(滾動(dòng)容器)元素的 scrollHeight 屬性獲取。用戶可以通過滾動(dòng)來改變列表在可視區(qū)域的顯示部分。

可視區(qū)域:滾動(dòng)容器元素的視覺可見區(qū)域。如果容器元素是 window 對(duì)象,可視區(qū)域就是瀏覽器的視口大小(即視覺視口);如果容器元素是某個(gè) div 元素,其高度是 300,右側(cè)有縱向滾動(dòng)條可以滾動(dòng),那么視覺可見的區(qū)域就是可視區(qū)域。

實(shí)現(xiàn)虛擬列表就是在處理用戶滾動(dòng)時(shí),要改變列表在可視區(qū)域的渲染部分,其具體步驟如下:

計(jì)算當(dāng)前可見區(qū)域起始數(shù)據(jù)的 startIndex

計(jì)算當(dāng)前可見區(qū)域結(jié)束數(shù)據(jù)的 endIndex

計(jì)算當(dāng)前可見區(qū)域的數(shù)據(jù),并渲染到頁面中

計(jì)算 startIndex 對(duì)應(yīng)的數(shù)據(jù)在整個(gè)列表中的偏移位置 startOffset,并設(shè)置到列表上

計(jì)算 endIndex 對(duì)應(yīng)的數(shù)據(jù)相對(duì)于可滾動(dòng)區(qū)域最底部的偏移位置 endOffset,并設(shè)置到列表上

建議參考下圖理解一下上面的步驟:

元素 L 代指當(dāng)前列表中的最后一個(gè)元素

從上圖可以看出,startOffsetendOffset 會(huì)撐開容器元素的內(nèi)容高度,讓其可持續(xù)的滾動(dòng);此外,還能保持滾動(dòng)條處于一個(gè)正確的位置。

為什么需要虛擬列表?

虛擬列表是對(duì)長列表的一種優(yōu)化方案。在前端開發(fā)中,會(huì)碰到一些不能使用分頁方式來加載列表數(shù)據(jù)的業(yè)務(wù)形態(tài),我們稱這種列表叫做長列表。比如,在一些外匯交易系統(tǒng)中,前端會(huì)準(zhǔn)實(shí)時(shí)的展示用戶的持倉情況(收益、虧損、手?jǐn)?shù)等),此時(shí)對(duì)于用戶的持倉列表一般是不能分頁的。

在本篇文章中,我們把長列表定義成數(shù)據(jù)長度大于 999,并且不能使用分頁的形式來展示的列表。

如果對(duì)長列表不作優(yōu)化,完整地渲染一個(gè)長列表,到底需要多長時(shí)間呢?接下來會(huì)寫一個(gè)簡單的 demo 來測(cè)試以下。

本文 demo 的測(cè)試環(huán)境:Macbook Pro(Core i7 2.2G, 16G), Chrome 69,React 16.4.1

在 demo 中,我們先測(cè)一下瀏覽器渲染 10000 個(gè)簡單的節(jié)點(diǎn)需要多長時(shí)間:

import React from "react"

const count = 10000

function createMarkup (doms) {
  return doms.length ? { __html: doms.join(" ") } : { __html: "" }
}

export default class DOM extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      simpleDOMs: []
    }

    this.onCreateSimpleDOMs = this.onCreateSimpleDOMs.bind(this)
  }

  onCreateSimpleDOMs () {
    const array = []

    for (var i = 0; i < count; i++) {
      array.push("
" + i + "
") } this.setState({ simpleDOMs: array }) } render () { return (

Creat large of DOMs:

) } }

當(dāng)點(diǎn)擊 Button 時(shí),會(huì)調(diào)用 onCreateSimpleDOMs 創(chuàng)建 10000 個(gè)簡單節(jié)點(diǎn)。從 Chrome 的 Performance 標(biāo)簽頁看到的數(shù)據(jù)如下:

從上圖可以看到,從 Event Click 到 Paint,總共用了大約 693ms,渲染時(shí)的主要時(shí)間消耗情況如下:

Recalculate Style:40.80ms

Layout:518.55ms

Update Layer Tree:11.84ms

在 Recalculate Style 和 Layout 階段,ReactDOM 調(diào)用了 setInnerHTML 方法,其內(nèi)部主要通過 innerHTML 方法,將創(chuàng)建好的 html 片段添加到對(duì)應(yīng)節(jié)點(diǎn)

然后,我們創(chuàng)建 10000 個(gè)稍微復(fù)雜點(diǎn)的節(jié)點(diǎn)。修改組件如下:

import React from "react"

function createMarkup (doms) {
  return doms.length ? { __html: doms.join(" ") } : { __html: "" }
}

export default class DOM extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      complexDOMs: []
    }

    this.onCreateComplexDOMs = this.onCreateComplexDOMs.bind(this)
  }

  onCreateComplexDOMs () {
    const array = []
    for (var i = 0; i < 5000; i++) {
      array.push(`
        

#${i} eligendi voluptatem quisquam

Modi autem fugiat maiores. Doloremque est sed quis qui nobis. Accusamus dolorem aspernatur sed rem.

`) } this.setState({ complexDOMs: array }) } render () { return (

Creat large of DOMs:

) } }

當(dāng)點(diǎn)擊 Button 時(shí),會(huì)調(diào)用 onCreateComplexDOMs。從 Chrome 的 Performance 標(biāo)簽頁看到的數(shù)據(jù)如下:

從上圖可以看到,從 Event Click 到 Paint,總共用了大約 964.2ms,渲染時(shí)的主要時(shí)間消耗情況如下:

Recalculate Style:117.07ms

Layout:538.00ms

Update Layer Tree:31.15ms

對(duì)于上述測(cè)試各進(jìn)行 5 次,然后取各指標(biāo)的平均值,統(tǒng)計(jì)結(jié)果如下:

- Recalculate Style Layout Update Layer Tree Total
渲染簡單節(jié)點(diǎn) 199.66ms 523.72ms 12.572ms 735.952ms
渲染復(fù)雜節(jié)點(diǎn) 114.684ms 806.05ms 31.328ms 952.512ms

Total = Recalculate Style + Layout + Update Layer Tree

demo 的測(cè)試代碼:test code

從上面的測(cè)試結(jié)果中可以看到,渲染 10000 個(gè)節(jié)點(diǎn)就需要 700ms+,實(shí)際業(yè)務(wù)中的列表每個(gè)節(jié)點(diǎn)都需要 20 個(gè)左右的節(jié)點(diǎn),布局也會(huì)復(fù)雜很多,在 Recalculate Style 和 Layout 階段也會(huì)耗費(fèi)更長的時(shí)間。那么,700ms 也僅能渲染 300 ~ 500 個(gè)左右的列表項(xiàng),所以完整的長列表渲染基本上很難達(dá)到業(yè)務(wù)上的要求的。而非完整的長列表渲染一般有兩種方式:按需渲染和延遲渲染(即懶渲染)。常見的無限滾動(dòng)便是延遲渲染的一種實(shí)現(xiàn),而虛擬列表則是按需渲染的一種實(shí)現(xiàn)。

延遲渲染不在本文討論范圍。接下來,本文會(huì)簡單介紹虛擬列表的一種實(shí)現(xiàn)方案。

實(shí)現(xiàn)

本章節(jié)將會(huì)創(chuàng)建一個(gè) VirtualizedList 組件,并結(jié)合代碼,慢慢梳理虛擬列表的實(shí)現(xiàn)。

為了簡化,我們?cè)O(shè)定 window 為滾動(dòng)容器元素,給 htmlbody 元素均添加樣式規(guī)則 height: 100%,設(shè)定可視區(qū)域?yàn)闉g覽器的窗口大小。VirtualizedList 在 DOM 元素的布局上將參考Twitter 的移動(dòng)端:

class VirtualizedList extends Component {
  constructor (props) {
    super(props)
    
    this.state = {
      startOffset: 0,
      endOffset: 0,
      visibleData: []
    }
    
    this.data = new Array(1000).fill(true)
    this.startIndex = 0
    this.endIndex = 0
    this.scrollTop = 0
  }
  
  render () {
    const {startOffset, endOffset} = this.state
    
    return (
      
{ // render list }
) } }

在虛擬列表上的實(shí)現(xiàn)上,也分為兩種情形:列表項(xiàng)是固定高度的和列表項(xiàng)是動(dòng)態(tài)高度的。

列表項(xiàng)是固定高度的

既然列表項(xiàng)是固定高度的,那約定沒個(gè)列表項(xiàng)的高度為 60,列表數(shù)據(jù)的長度為 1000。

首先,我們根據(jù)可視區(qū)域的高度估算可視區(qū)域能渲染的元素個(gè)數(shù):

const height = 60
const bufferSize = 5
// ...

this.visibleCount = Math.ceil(window.clientHeight / height)

然后,計(jì)算 startIndexendIndex,并先初始化初次需要渲染的數(shù)據(jù):

// ...

updateVisibleData (scrollTop) {
  const visibleData = this.data.slice(this.startIndex, this.endIndex)
  const endOffset = (this.data.length - this.endIndex) * height
    
  this.setState({
    startOffset: 0,
    endOffset,
    visibleData
  })
}

componentDidMount () {
  // 計(jì)算可渲染的元素個(gè)數(shù)
  this.visibleCount = Math.ceil(window.innerHeight / height) + bufferSize
  this.endIndex = this.startIndex + this.visibleCount
  this.updateVisibleData()
}

如上文所說,endOffset 是計(jì)算 endIndex 對(duì)應(yīng)的數(shù)據(jù)相對(duì)于可滾動(dòng)區(qū)域底部的偏移位置。在本 demo 中,可滾動(dòng)區(qū)域的高度就是 1000 60,因而 endIndex 對(duì)應(yīng)的數(shù)據(jù)相距底部的偏移就是 (1000 - endIndex) 60。

由于是初始化初次需要渲染的數(shù)據(jù),因而 startOffset 的初始值是 0。

根據(jù)上述代碼,可以得知,要計(jì)算可見區(qū)域需要渲染的數(shù)據(jù),只要計(jì)算出 startIndex 就行,因?yàn)?visibleCount 是一個(gè)定值,bufferSize 是一個(gè)緩沖值,用來增加一定的緩存區(qū)域,讓正常滑動(dòng)速度的時(shí)候不會(huì)顯得那么突兀。而 endIndex 的值就等于 startIndex 加上 visibleCount;同時(shí),當(dāng)用戶滾動(dòng)改變可見區(qū)域的數(shù)據(jù)時(shí),還需要計(jì)算 startOffset 的值,以保證新的數(shù)據(jù)會(huì)出現(xiàn)在用戶瀏覽器的視口中:

如果不計(jì)算 startOffset 的值,那本應(yīng)該渲染在可視區(qū)域內(nèi)的元素會(huì)渲染到可視區(qū)域之外。從上圖可以看到,startOffset 的值就是元素8的上邊框 (可視區(qū)域內(nèi)最上面一個(gè)元素) 到元素1的上邊框的偏移量。元素8稱為 錨點(diǎn)元素,即可視區(qū)域內(nèi)的第一個(gè)元素。 因而,我們需要定義一個(gè)變量來緩存錨點(diǎn)元素的一些位置信息,同時(shí)也要緩存已渲染的元素的位置信息:

// ...
// 緩存已渲染元素的位置信息
this.cache = []
// 緩存錨點(diǎn)元素的位置信息
this.anchorItem = {
  index: 0, // 錨點(diǎn)元素的索引值
  top: 0, // 錨點(diǎn)元素的頂部距離第一個(gè)元素的頂部的偏移量(即 startOffset)
  bottom: 0 // 錨點(diǎn)元素的底部距離第一個(gè)元素的頂部的偏移量
}
// ...

cachePosition (node, index) {
  const rect = node.getBoundingClientRect()
  const top = rect.top + window.pageYOffset
  
  this.cache.push({
    index,
    top,
    bottom: top + height
  })
}

// ...

方法 cachePosition 會(huì)在每個(gè)列表項(xiàng)組件渲染完后(componentDidMount)進(jìn)行調(diào)用,node 是對(duì)應(yīng)的列表項(xiàng)節(jié)點(diǎn)元素,index 是節(jié)點(diǎn)的索引值:

// Item.jsx

// ...
componentDidMount () {
  this.props.cachePosition(this.node, this.props.index)
}

render () {
  /* eslint-disable-next-line */
  const {index} = this.props

  return (
    
{ this.node = node }}>

#${index} eligendi voluptatem quisquam

Modi autem fugiat maiores. Doloremque est sed quis qui nobis. Accusamus dolorem aspernatur sed rem.

) } // ...

緩存了錨點(diǎn)元素和已渲染元素的位置信息之后,接下來就可以處理用戶的滾動(dòng)行為了。以用戶向下滾動(dòng)(scrollTop 值增大的方向)為例:

// ...
// 計(jì)算 startIndex 和 endIndex
updateBoundaryIndex (scrollTop) {
  scrollTop = scrollTop || 0
  //用戶正常滾動(dòng)下,根據(jù) scrollTop 找到新的錨點(diǎn)元素位置
  const anchorItem = this.cache.find(item => item.bottom >= scrollTop)

  this.anchorItem = {
    ...anchorItem
  }

  this.startIndex = this.anchorItem.index
  this.endIndex = this.startIndex + this.visibleCount
}

// 滾動(dòng)事件處理函數(shù)
handleScroll (e) {
  if (!this.doc) {
    // 兼容 iOS Safari/Webview
    this.doc = window.document.body.scrollTop ? window.document.body : window.document.documentElement
  }

  const scrollTop = this.doc.scrollTop
  if (scrollTop > this.scrollTop) {
    if (scrollTop > this.anchorItem.bottom) {
      this.updateBoundaryIndex(scrollTop)
      this.updateVisibleData()
    }
  } else if (scrollTop < this.scrollTop) {
    // 向上滾動(dòng)(`scrollTop` 值減小的方向)
  }

  this.scrollTop = scrollTop
}
// ...

在滾動(dòng)事件處理函數(shù)中,會(huì)去更新 startIndexendIndex 以及新的錨點(diǎn)元素的位置信息(即更新 startOffset),然后就可以動(dòng)態(tài)的去更新可視區(qū)域的渲染數(shù)據(jù)了:

完整的代碼在可以戳:固定高度的虛擬列表實(shí)現(xiàn)
列表項(xiàng)是動(dòng)態(tài)高度的

這種情形下,實(shí)現(xiàn)的思路和列表項(xiàng)固高大同小異。而小異之處就在于緩存列表項(xiàng)的位置信息時(shí),怎么拿到列表項(xiàng)的精確高度?首先要更改 cachePosition 的部分邏輯:

// ...
cachePosition (node, index) {
  const rect = node.getBoundingClientRect()
  const top = rect.top + window.pageYOffset

  this.cache.push({
    index,
    top,
    bottom: top + rect.height // 將 height 更為 rect.height
  })
}
// ...

由于列表項(xiàng)的高度不固定,那要怎么計(jì)算 visibleCount 呢?我們先考慮每個(gè)列表項(xiàng)只是渲染一些純文本。在實(shí)際項(xiàng)目中,有的列表項(xiàng)可能只有一行文本,有的列表項(xiàng)可能有多行文本,此時(shí),我們要基于項(xiàng)目的實(shí)際情況,給列表項(xiàng)一個(gè)預(yù)估的高度estimatedItemHeight。

比如,有一個(gè)長列表要渲染用戶的文章摘要,并規(guī)定摘要顯示不超過三行,那么我們?nèi)×斜淼那?10 個(gè)列表項(xiàng)的高度平均值作為預(yù)估高度。當(dāng)然,為了預(yù)估高度更精確,我們是可以擴(kuò)大取樣樣本的。

既然有了預(yù)估高度,那么將原先代碼中的 height 替換成 estimatedItemHeight,就可以計(jì)算出 visibleCount 了:

// ...
const estimatedItemHeight = 80

// ...

// 計(jì)算可渲染的元素個(gè)數(shù)
this.visibleCount = Math.ceil(window.innerHeight / estimatedItemHeight) + bufferSize

// ...

我們通過 faker.js 來創(chuàng)建一些隨機(jī)數(shù)據(jù),并賦值給 data

// ...
function fakerData () {
  const a = []
  for (let i = 0; i < 1000; i++) {
    a.push({
      id: i,
      words: faker.lorem.words(),
      paragraphs: faker.lorem.sentences()
    })
  }

  return a
}
// ...

this.data = fakerData()

// ...

修改一下列表項(xiàng)的 render 邏輯,其它不變:

// Item.jsx

// ...

render () {
  /* eslint-disable-next-line */
  const {index, item} = this.props

  return (
    
{ this.node = node }}>

#${index} {item.words}

{item.paragraphs}

) } // ...

此時(shí),列表項(xiàng)的高度已經(jīng)是動(dòng)態(tài)的了,根據(jù)渲染的實(shí)際情況,我們給的預(yù)估高度是 80:

完整的代碼在可以戳:動(dòng)態(tài)高度的虛擬列表實(shí)現(xiàn)

那如果列表項(xiàng)渲染的不是純文本呢?比如渲染的是圖文,那在 Item 組件的 componentDidMount 去調(diào)用 cachePosition 方法時(shí),能拿到對(duì)應(yīng)節(jié)點(diǎn)的正確高度嗎?在渲染圖文的情況下,因?yàn)閳D片會(huì)發(fā)起網(wǎng)絡(luò)請(qǐng)求,此時(shí)并不能保證在列表項(xiàng)組件掛載(執(zhí)行 componentDidMount)的時(shí)候圖片渲染好了,那此時(shí)對(duì)應(yīng)節(jié)點(diǎn)的高度就是不準(zhǔn)確的,因而在用戶滾動(dòng)改變可見區(qū)域渲染的數(shù)據(jù)時(shí),就可能出現(xiàn)元素相互重疊的情況:

在這種情況下,如果我們能監(jiān)聽 Item 組件節(jié)點(diǎn)的大小變化就能獲取其正確的高度了。ResizeObserver 或許就可以滿足我們的需求,其提供了監(jiān)聽 DOM 元素大小變化的能力,但在撰寫本文時(shí),僅 Chrome 67 及以上版本支持,其它主流瀏覽器均為提供支持。以下是我搜集的一些資料,供你參考(自備梯子):

ResizeObserver: It’s Like document.onresize for Elements

ResizeObserver

caniuse#resizeobserver

總結(jié)

在本文中,首先對(duì)虛擬列表進(jìn)行了簡單的定義,然后從長列表的角度分析了為什么需要虛擬列表,最后就列表項(xiàng)固高和不固高兩個(gè)場(chǎng)景下以一個(gè)簡單的 demo 詳細(xì)講述了虛擬列表的實(shí)現(xiàn)思路。

在列表項(xiàng)是動(dòng)態(tài)高度的場(chǎng)景下,分析了渲染純文本和圖文混合的場(chǎng)景。前者給出了一個(gè)具體的 demo,針對(duì)后者對(duì)于怎么監(jiān)聽元素大小的變化提供了參考的 ResizeObserver 方案?;?ResizeObserver 的方案呢,我也實(shí)現(xiàn)了一個(gè)支持渲染圖文混合(當(dāng)然也支持純文本)的虛擬列表組件 react-virtual-list,供你參考。

當(dāng)然,這并不是唯一一種實(shí)現(xiàn)虛擬列表的方案。在組件 react-virtual-list 的實(shí)現(xiàn)過程中,也閱讀了不同虛擬列表組件的源碼,如: react-tiny-virtual-list、react-window、react-virtualized 等,后續(xù)的系列文章我會(huì)從源碼的角度逐一分析。

原文:https://github.com/dwqs/blog/...

參考

Complexities of an Infinite Scroller

Infinite List and React

聊聊前端開發(fā)中的長列表

再談前端虛擬列表的實(shí)現(xiàn)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98491.html

相關(guān)文章

  • web 應(yīng)用常見安全漏洞一覽

    摘要:應(yīng)用常見安全漏洞一覽注入注入就是通過給應(yīng)用接口傳入一些特殊字符,達(dá)到欺騙服務(wù)器執(zhí)行惡意的命令。此外,適當(dāng)?shù)臋?quán)限控制不曝露必要的安全信息和日志也有助于預(yù)防注入漏洞。 web 應(yīng)用常見安全漏洞一覽 1. SQL 注入 SQL 注入就是通過給 web 應(yīng)用接口傳入一些特殊字符,達(dá)到欺騙服務(wù)器執(zhí)行惡意的 SQL 命令。 SQL 注入漏洞屬于后端的范疇,但前端也可做體驗(yàn)上的優(yōu)化。 原因 當(dāng)使用外...

    darkerXi 評(píng)論0 收藏0
  • web 應(yīng)用常見安全漏洞一覽

    摘要:應(yīng)用常見安全漏洞一覽注入注入就是通過給應(yīng)用接口傳入一些特殊字符,達(dá)到欺騙服務(wù)器執(zhí)行惡意的命令。此外,適當(dāng)?shù)臋?quán)限控制不曝露必要的安全信息和日志也有助于預(yù)防注入漏洞。 web 應(yīng)用常見安全漏洞一覽 1. SQL 注入 SQL 注入就是通過給 web 應(yīng)用接口傳入一些特殊字符,達(dá)到欺騙服務(wù)器執(zhí)行惡意的 SQL 命令。 SQL 注入漏洞屬于后端的范疇,但前端也可做體驗(yàn)上的優(yōu)化。 原因 當(dāng)使用外...

    Panda 評(píng)論0 收藏0
  • 在React項(xiàng)目中,如何優(yōu)雅優(yōu)化長列表

    摘要:合理的優(yōu)化長列表,可以提升用戶體驗(yàn)。這樣保證了無論如何滾動(dòng),真實(shí)渲染出的節(jié)點(diǎn)只有可視區(qū)內(nèi)的列表元素。具體效果如下圖所示對(duì)于比無優(yōu)化的情況,優(yōu)化后的虛擬列表渲染速度提升很明顯。是基于來實(shí)現(xiàn)的,但是是一個(gè)維的列表,而不是網(wǎng)狀。 ??對(duì)于較長的列表,比如1000個(gè)數(shù)組的數(shù)據(jù)結(jié)構(gòu),如果想要同時(shí)渲染這1000個(gè)數(shù)據(jù),生成相應(yīng)的1000個(gè)原生dom,我們知道原生的dom元素是很復(fù)雜的,如果長列表...

    yearsj 評(píng)論0 收藏0
  • 在React項(xiàng)目中,如何優(yōu)雅優(yōu)化長列表

    摘要:合理的優(yōu)化長列表,可以提升用戶體驗(yàn)。這樣保證了無論如何滾動(dòng),真實(shí)渲染出的節(jié)點(diǎn)只有可視區(qū)內(nèi)的列表元素。具體效果如下圖所示對(duì)于比無優(yōu)化的情況,優(yōu)化后的虛擬列表渲染速度提升很明顯。是基于來實(shí)現(xiàn)的,但是是一個(gè)維的列表,而不是網(wǎng)狀。 ??對(duì)于較長的列表,比如1000個(gè)數(shù)組的數(shù)據(jù)結(jié)構(gòu),如果想要同時(shí)渲染這1000個(gè)數(shù)據(jù),生成相應(yīng)的1000個(gè)原生dom,我們知道原生的dom元素是很復(fù)雜的,如果長列表...

    Java_oldboy 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<