使用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 Native 開發(fā)環(huán)境
這篇文章主要介紹了搭建 React Native 開發(fā)環(huán)境的詳細過程,本文通過圖文指令給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08
react+react-beautiful-dnd實現(xiàn)代辦事項思路詳解
這篇文章主要介紹了react+react-beautiful-dnd實現(xiàn)代辦事項,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06
React創(chuàng)建組件的三種方式及其區(qū)別是什么
在React中,創(chuàng)建組件的三種主要方式是函數(shù)式組件、類組件和使用React Hooks的函數(shù)式組件,本文就詳細的介紹一下如何使用,感興趣的可以了解一下2023-08-08
react axios配置代理(proxy),如何解決本地開發(fā)時的跨域問題
這篇文章主要介紹了react axios配置代理(proxy),如何解決本地開發(fā)時的跨域問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07
React父組件數(shù)據(jù)實時更新了,子組件沒有更新的問題
這篇文章主要介紹了React父組件數(shù)據(jù)實時更新了,子組件沒有更新的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03

