使用react-virtualized实现图片动态高度长列表的问题


Posted in Javascript onMay 28, 2021

虚拟列表是一种根据滚动容器元素的可视区域来渲染长列表数据中某一个部分数据的技术。虚拟列表是对长列表场景一种常见的优化,毕竟很少有人在列表中渲染上百个子元素,只需要在滚动条横向或纵向滚动时将可视区域内的元素渲染出即可。

开发中遇到的问题

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'),
);

使用react-virtualized实现图片动态高度长列表的问题

其中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 virtualized长列表的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
初学js插入节点appendChild insertBefore使用方法
Jul 04 Javascript
Javascript面向对象编程(二) 构造函数的继承
Aug 28 Javascript
多个表单中如何获得这个文件上传的网址实现js代码
Mar 25 Javascript
jquery实现页面关键词高亮显示的方法
Mar 12 Javascript
node.js express安装及示例网站搭建方法(分享)
Aug 22 Javascript
在点击div中的p时,如何阻止事件冒泡
Feb 07 Javascript
深入学习 JavaScript中的函数调用
Mar 23 Javascript
JS设置随机出现2个数字的实例代码
Jul 19 Javascript
JS 实现分页打印功能
May 16 Javascript
three.js搭建室内场景教程
Dec 30 Javascript
详解基于Wepy开发小程序插件(推荐)
Aug 01 Javascript
js中实现继承的五种方法
Jan 25 Javascript
element多个表单校验的实现
May 27 #Javascript
springboot+VUE实现登录注册
May 27 #Vue.js
vue+springboot实现登录验证码
vue+spring boot实现校验码功能
May 27 #Vue.js
vue-cropper组件实现图片切割上传
May 27 #Vue.js
vue-cropper插件实现图片截取上传组件封装
May 27 #Vue.js
HTML+VUE分页实现炫酷物联网大屏功能
You might like
mysql,mysqli,PDO的各自不同介绍
2012/09/19 PHP
PHP实现数组递归转义的方法
2014/08/28 PHP
PHP制作百度词典查词采集器
2015/01/29 PHP
Ajax中的JSON格式与php传输过程全面解析
2017/11/14 PHP
thinkphp5框架扩展redis类方法示例
2019/05/06 PHP
Nigma vs Liquid BO3 第一场2.13
2021/03/10 DOTA
js 内存释放问题
2010/04/25 Javascript
js中eval详解
2012/03/30 Javascript
jquery仅用6行代码实现滑动门效果
2015/09/07 Javascript
JavaScript function函数种类详解
2016/02/22 Javascript
JS实现的自定义水平滚动字体插件完整实例
2016/06/17 Javascript
VueJs路由跳转——vue-router的使用详解
2017/01/10 Javascript
JavaScript实现向select下拉框中添加和删除元素的方法
2017/03/07 Javascript
快速解决bootstrap下拉菜单无法隐藏的问题
2018/08/10 Javascript
Python中用altzone()方法处理时区的教程
2015/05/22 Python
浅谈Python实现贪心算法与活动安排问题
2017/12/19 Python
在Python 不同级目录之间模块的调用方法
2019/01/19 Python
PyQt5实现简单数据标注工具
2019/03/18 Python
numpy.where() 用法详解
2019/05/27 Python
python使用装饰器作日志处理的方法
2019/07/11 Python
python中的反斜杠问题深入讲解
2019/08/12 Python
python协程gevent案例 爬取斗鱼图片过程解析
2019/08/27 Python
python装饰器的特性原理详解
2019/12/25 Python
Jupyter Notebook 文件默认目录的查看以及更改步骤
2020/04/14 Python
浅谈tensorflow使用张量时的一些注意点tf.concat,tf.reshape,tf.stack
2020/06/23 Python
解决PyCharm无法使用lxml库的问题(图解)
2020/12/22 Python
美国最大的香水出口:FragranceX.com
2017/11/04 全球购物
毕业自我鉴定范文
2013/11/06 职场文书
计算机专业推荐信范文
2013/11/20 职场文书
大学生实习感言
2014/01/16 职场文书
少先队学雷锋活动总结范文
2014/03/09 职场文书
事业单位考核材料
2014/05/21 职场文书
离职感谢信
2015/01/21 职场文书
演讲比赛主持词
2015/06/29 职场文书
志愿服务心得体会
2016/01/15 职场文书
警用民用对讲机找不同
2022/02/18 无线电