使用react-virtualized實現圖片動態高度長列表的問題
阿新 • • 發佈:2021-05-28
虛擬列表是一種根據滾動容器元素的可視區域來渲染長列表資料中某一個部分資料的技術。虛擬列表是對長列表場景一種常見的優化,畢竟很少有人在列表中渲染上百個子元素,只需要在滾動條橫向或縱向滾動時將可視區域內的元素渲染出即可。
開發中遇到的問題
1.長列表中的圖片要保持原圖片相同的比例,那縱向滾動在寬度不變的情況下,每張圖片的高度就是動態的,當該列表項高度發生了變化,會影響該列表項及其之後所有列表項的位置資訊。
2.圖片width,height必須在圖片載入完成後才能獲得.
解決方案
我們使用react-virtualized中list元件,官方給出的例子
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 youhttp://www.cppcns.comr list ReactDOM.render( <List width={300} height={300} rowCount={list.length} rowHeight={20} rowRenderer={rowRenderer} />,document.getElementById('example'),);
其中rowHeight是每一行的高度,可以傳入固定高度也可以傳入function。每次子元素高度改變需要呼叫recomputeRowHeights方法,指定索引後重新計算行高度和偏移量。
具體實現
const ImgHeightComponent = ({ imgUrl,onHeightReady,height,width }) => { const [style,setStyle] = useState({ height,width,display: 'block',}) const getImgWithAndHeight = (url) => { return new Promiswww.cppcns.come((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,}) onHeightReady(currentHeight) }) },[]) return <img src={imgUrl} alt="使用react-virtualized實現圖片動態高度長列表的問題" style={style} /> }
先寫一個獲取圖片高度的元件,通過定時迴圈檢測獲取並計算出高度傳給父元件。
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 = (heigKlZyfcxht,index) => { this.setState( (state) => { const flag = state.heights.some((item) => item.index === index) if (!flag) { 程式設計客棧 return { heights: [ ...state.heights,{ index,},],} } 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="使用react-virtualized實現圖片動態高度長列表的問題" 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方法收集所有圖片的高度,並在每一次高度改變呼叫List元件的recomputeRowHeights方法通知元件重新計算高度和偏移。到這裡基本已經解決遇到的問題。
實際效果
小結
目前只是使用react-virtualized來完成圖片長列表實現,具體react-virtualized內部實現還需要進一步研究。
以上就是用react-virtualized實現圖片動態高度長列表的詳細內容,更多關於react virtualized長列表的資料請關注我們其它相關文章!