使用react-virtualized实现图片动态高度长列表的问题
虚拟列表是一种根据滚动容器元素的可视区域来渲染长列表数据中某一个部分数据的技术。虚拟列表是对长列表场景一种常见的优化,毕竟很少有人在列表中渲染上百个子元素,只需要在滚动条横向或纵向滚动时将可视区域内的元素渲染出即可。
开发中遇到的问题
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 your 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 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} /> }
先写一个获取图片高度的组件,通过定时循环检测获取并计算出高度传给父组件。
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方法收集所有图片的高度,并在每一次高度改变调用List组件的recomputeRowHeights方法通知组件重新计算高度和偏移。到这里基本已经解决遇到的问题。
实际效果
小结
目前只是使用react-virtualized来完成图片长列表实现,具体react-virtualized内部实现还需要进一步研究。
以上就是用react-virtualized实现图片动态高度长列表的详细内容,更多关于react virtualized长列表的资料请关注脚本之家其它相关文章!
相关文章
react+react-beautiful-dnd实现代办事项思路详解
这篇文章主要介绍了react+react-beautiful-dnd实现代办事项,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2022-06-06react axios配置代理(proxy),如何解决本地开发时的跨域问题
这篇文章主要介绍了react axios配置代理(proxy),如何解决本地开发时的跨域问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2023-07-07
最新评论