使用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 相关文章推荐
User Scripts: Video Download by User Scripts
May 14 Javascript
ext for eclipse插件安装方法
Apr 27 Javascript
另一个javascript小测验(代码集合)
Jul 27 Javascript
JavaScript高级程序设计 读书笔记之十一 内置对象Global
Mar 07 Javascript
Extjs3.0 checkboxGroup 动态添加item实现思路
Aug 14 Javascript
JavaScript使用Max函数返回两个数字中较大数的方法
Apr 06 Javascript
jQuery实现点击任意位置弹出层外关闭弹出层效果
Oct 19 Javascript
详解vue.js的devtools安装
May 26 Javascript
vue.js简单配置axios的方法详解
Dec 13 Javascript
JS实现统计字符串中字符出现个数及最大个数功能示例
Jun 04 Javascript
对layui中表单元素的使用详解
Aug 15 Javascript
vue实现菜单切换功能
May 08 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
javascript实现的像java、c#之类的sleep暂停的函数代码
2010/03/04 Javascript
转义字符(\)对JavaScript中JSON.parse的影响概述
2013/07/17 Javascript
深入理解javascript原型链和继承
2014/09/23 Javascript
JavaScript控制网页平滑滚动到指定元素位置的方法
2015/04/17 Javascript
JS+CSS实现带小三角指引的滑动门效果
2015/09/22 Javascript
基于javascript显示当前时间以及倒计时功能
2016/03/18 Javascript
zTree插件下拉树使用入门教程
2016/04/11 Javascript
jQuery 获取多选框的值及多选框中文的函数
2016/05/16 Javascript
AngularJS基础 ng-mouseover 指令简单示例
2016/08/02 Javascript
AngularJS使用angular.bootstrap完成模块手动加载的方法分析
2017/01/19 Javascript
jQuery模拟窗口抖动效果
2017/03/15 Javascript
详解vue-router 2.0 常用基础知识点之router-link
2017/05/10 Javascript
关于react-router的几种配置方式详解
2017/07/24 Javascript
js捆绑TypeScript声明文件的方法教程
2018/04/13 Javascript
vue全局使用axios的方法实例详解
2018/11/22 Javascript
Python的Django框架可适配的各种数据库介绍
2015/07/15 Python
Python采集代理ip并判断是否可用和定时更新的方法
2018/05/07 Python
Python不同目录间进行模块调用的实现方法
2019/01/29 Python
python selenium 查找隐藏元素 自动播放视频功能
2019/07/24 Python
使用python写的opencv实时监测和解析二维码和条形码
2019/08/14 Python
python实现回旋矩阵方式(旋转矩阵)
2019/12/04 Python
pycharm 对代码做静态检查操作
2020/06/09 Python
使用Html5 Stream开发实时监控系统
2020/06/02 HTML / CSS
联想中国官方商城:Lenovo China
2017/10/18 全球购物
阿根廷旅游网站:almundo阿根廷
2018/02/12 全球购物
TIME时代杂志台湾总代理:台时亚洲
2018/10/22 全球购物
医药工作者的求职信范文
2013/09/21 职场文书
信息管理专业学生自荐信格式
2013/09/22 职场文书
公司年会晚宴演讲稿
2014/01/06 职场文书
岗位竞聘演讲稿
2014/01/10 职场文书
《乡愁》教学反思
2014/02/18 职场文书
安全生产管理合理化建议书
2014/03/12 职场文书
美国旅游签证工作证明
2014/10/14 职场文书
2015高三毕业寄语赠言
2015/02/27 职场文书
新闻通讯稿范文
2015/07/22 职场文书
Python 绘制多因子柱状图
2022/05/11 Python