使用react-virtualized實(shí)現(xiàn)圖片動(dòng)態(tài)高度長列表的問題
虛擬列表是一種根據(jù)滾動(dòng)容器元素的可視區(qū)域來渲染長列表數(shù)據(jù)中某一個(gè)部分?jǐn)?shù)據(jù)的技術(shù)。虛擬列表是對(duì)長列表場景一種常見的優(yōu)化,畢竟很少有人在列表中渲染上百個(gè)子元素,只需要在滾動(dòng)條橫向或縱向滾動(dòng)時(shí)將可視區(qū)域內(nèi)的元素渲染出即可。
開發(fā)中遇到的問題
1.長列表中的圖片要保持原圖片相同的比例,那縱向滾動(dòng)在寬度不變的情況下,每張圖片的高度就是動(dòng)態(tài)的,當(dāng)該列表項(xiàng)高度發(fā)生了變化,會(huì)影響該列表項(xiàng)及其之后所有列表項(xiàng)的位置信息。
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方法,指定索引后重新計(jì)算行高度和偏移量。
具體實(shí)現(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} /> }
先寫一個(gè)獲取圖片高度的組件,通過定時(shí)循環(huán)檢測獲取并計(jì)算出高度傳給父組件。
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ì)算高度和偏移。到這里基本已經(jīng)解決遇到的問題。
實(shí)際效果
小結(jié)
目前只是使用react-virtualized來完成圖片長列表實(shí)現(xiàn),具體react-virtualized內(nèi)部實(shí)現(xiàn)還需要進(jìn)一步研究。
以上就是用react-virtualized實(shí)現(xiàn)圖片動(dòng)態(tài)高度長列表的詳細(xì)內(nèi)容,更多關(guān)于react virtualized長列表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
react后臺(tái)系統(tǒng)最佳實(shí)踐示例詳解
這篇文章主要為大家介紹了react后臺(tái)系統(tǒng)最佳實(shí)踐示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01教你快速搭建 React Native 開發(fā)環(huán)境
這篇文章主要介紹了搭建 React Native 開發(fā)環(huán)境的詳細(xì)過程,本文通過圖文指令給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08react+react-beautiful-dnd實(shí)現(xiàn)代辦事項(xiàng)思路詳解
這篇文章主要介紹了react+react-beautiful-dnd實(shí)現(xiàn)代辦事項(xiàng),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06React+CSS 實(shí)現(xiàn)繪制橫向柱狀圖
這篇文章主要介紹了React+CSS 實(shí)現(xiàn)繪制橫向柱狀圖,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09React創(chuàng)建組件的三種方式及其區(qū)別是什么
在React中,創(chuàng)建組件的三種主要方式是函數(shù)式組件、類組件和使用React Hooks的函數(shù)式組件,本文就詳細(xì)的介紹一下如何使用,感興趣的可以了解一下2023-08-08react axios配置代理(proxy),如何解決本地開發(fā)時(shí)的跨域問題
這篇文章主要介紹了react axios配置代理(proxy),如何解決本地開發(fā)時(shí)的跨域問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07React父組件數(shù)據(jù)實(shí)時(shí)更新了,子組件沒有更新的問題
這篇文章主要介紹了React父組件數(shù)據(jù)實(shí)時(shí)更新了,子組件沒有更新的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03