使用react-virtualized實現(xiàn)圖片動態(tài)高度長列表的問題
虛擬列表是一種根據(jù)滾動容器元素的可視區(qū)域來渲染長列表數(shù)據(jù)中某一個部分數(shù)據(jù)的技術(shù)。虛擬列表是對長列表場景一種常見的優(yōu)化,畢竟很少有人在列表中渲染上百個子元素,只需要在滾動條橫向或縱向滾動時將可視區(qū)域內(nèi)的元素渲染出即可。
開發(fā)中遇到的問題
1.長列表中的圖片要保持原圖片相同的比例,那縱向滾動在寬度不變的情況下,每張圖片的高度就是動態(tài)的,當該列表項高度發(fā)生了變化,會影響該列表項及其之后所有列表項的位置信息。
2.圖片width,height必須在圖片加載完成后才能獲得.
解決方案
我們使用react-virtualized中l(wèi)ist組件,官方給出的例子
import React from 'react';
import ReactDOM from 'react-dom';
import {List} from 'react-virtualized';
// List data as an array of strings
const list = [
'Brian Vaughn',
// And so on...
];
function rowRenderer({
key, // Unique key within array of rows
index, // Index of row within collection
isScrolling, // The List is currently being scrolled
isVisible, // This row is visible within the List (eg it is not an overscanned row)
style, // Style object to be applied to row (to position it)
}) {
return (
<div key={key} style={style}>
{list[index]}
</div>
);
}
// Render your list
ReactDOM.render(
<List
width={300}
height={300}
rowCount={list.length}
rowHeight={20}
rowRenderer={rowRenderer}
/>,
document.getElementById('example'),
);

其中rowHeight是每一行的高度,可以傳入固定高度也可以傳入function。每次子元素高度改變需要調(diào)用recomputeRowHeights方法,指定索引后重新計算行高度和偏移量。
具體實現(xiàn)
const ImgHeightComponent = ({ imgUrl, onHeightReady, height, width }) => {
const [style, setStyle] = useState({
height,
width,
display: 'block',
})
const getImgWithAndHeight = (url) => {
return new Promise((resolve, reject) => {
var img = new Image()
// 改變圖片的src
img.src = url
let set = null
const onload = () => {
if (img.width || img.height) {
//圖片加載完成
clearInterval(set)
resolve({ width: img.width, height: img.height })
}
}
set = setInterval(onload, 40)
})
}
useEffect(() => {
getImgWithAndHeight(imgUrl).then((size) => {
const currentHeight = size.height * (width / size.width)
setStyle({
height: currentHeight,
width: width,
display: 'block',
})
onHeightReady(currentHeight)
})
}, [])
return <img src={imgUrl} alt='' style={style} />
}
先寫一個獲取圖片高度的組件,通過定時循環(huán)檢測獲取并計算出高度傳給父組件。
import React, { useState, useEffect, useRef } from 'react'
import styles from './index.scss'
import { AutoSizer } from 'react-virtualized/dist/commonjs/AutoSizer'
import { List } from 'react-virtualized/dist/commonjs/List'
export default class DocumentStudy extends React.Component {
constructor(props) {
super(props)
this.state = {
list: [],
heights: [],
autoWidth:900,
autoHeight: 300
}
}
handleHeightReady = (height, index) => {
this.setState(
(state) => {
const flag = state.heights.some((item) => item.index === index)
if (!flag) {
return {
heights: [
...state.heights,
{
index,
height,
},
],
}
}
return {
heights: state.heights,
}
},
() => {
this.listRef.recomputeRowHeights(index)
},
)
}
getRowHeight = ({ index }) => {
const row = this.state.heights.find((item) => item.index === index)
return row ? row.height : this.state.autoHeight
}
renderItem = ({ index, key, style }) => {
const { list, autoWidth, autoHeight } = this.state
if (this.state.heights.find((item) => item.index === index)) {
return (
<div key={key} style={style}>
<img src={list[index].imgUrl} alt='' style={{width: '100%'}}/>
</div>
)
}
return (
<div key={key} style={style}>
<ImgHeightComponent
imgUrl={list[index].imgUrl}
width={autoWidth}
height={autoHeight}
onHeightReady={(height) => {
this.handleHeightReady(height, index)
}}
/>
</div>
)
}
render() {
const { list } = this.state
return (
<>
<div style={{ height: 1000 }}>
<AutoSizer>
{({ width, height }) => (
<List
ref={(ref) => (this.listRef = ref)}
width={width}
height={height}
overscanRowCount={10}
rowCount={list.length}
rowRenderer={this.renderItem}
rowHeight={this.getRowHeight}
/>
)}
</AutoSizer>
</div>
</>
)
}
}
父組件通過handleHeightReady方法收集所有圖片的高度,并在每一次高度改變調(diào)用List組件的recomputeRowHeights方法通知組件重新計算高度和偏移。到這里基本已經(jīng)解決遇到的問題。
實際效果

小結(jié)
目前只是使用react-virtualized來完成圖片長列表實現(xiàn),具體react-virtualized內(nèi)部實現(xiàn)還需要進一步研究。
以上就是用react-virtualized實現(xiàn)圖片動態(tài)高度長列表的詳細內(nèi)容,更多關(guān)于react virtualized長列表的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React?SSR架構(gòu)Stream?Rendering與Suspense?for?Data?Fetching
這篇文章主要為大家介紹了React?SSR架構(gòu)Stream?Rendering與Suspense?for?Data?Fetching解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03
react 實現(xiàn)圖片正在加載中 加載完成 加載失敗三個階段的原理解析
這篇文章主要介紹了react 實現(xiàn)圖片正在加載中 加載完成 加載失敗三個階段的,通過使用loading的圖片來占位,具體原理解析及實現(xiàn)代碼跟隨小編一起通過本文學(xué)習吧2021-05-05
react中的forwardRef 和memo的區(qū)別解析
forwardRef和memo是React中用于性能優(yōu)化和組件復(fù)用的兩個高階函數(shù),本文給大家介紹react中的forwardRef 和memo的區(qū)別及適用場景,感興趣的朋友跟隨小編一起看看吧2023-10-10
useEffect如何通過form.getFieldValue(‘xxx‘)監(jiān)聽Form表單變化
這篇文章主要介紹了useEffect如何通過form.getFieldValue(‘xxx‘)監(jiān)聽Form表單變化問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03
在react-router4中進行代碼拆分的方法(基于webpack)
這篇文章主要介紹了在react-router4中進行代碼拆分的方法(基于webpack),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03

