使用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 相关文章推荐
textContent在Firefox下与innerText等效的属性
May 12 Javascript
浅谈Javascript嵌套函数及闭包
Nov 09 Javascript
Ext.get() 和 Ext.query()组合使用实现最灵活的取元素方式
Sep 26 Javascript
JQuery DataTable删除行后的页面更新利用Ajax解决
May 17 Javascript
jQuery添加和删除指定标签的方法
Dec 16 Javascript
javascript每日必学之循环
Feb 19 Javascript
jQuery实现页面评论栏中访客信息自动填写功能的方法
May 23 Javascript
详解微信小程序 登录获取unionid
Jun 27 Javascript
jQuery选择器之子元素选择器详解
Sep 18 jQuery
JS笛卡尔积算法与多重数组笛卡尔积实现方法示例
Dec 01 Javascript
vue2.0组件之间传值、通信的多种方式(干货)
Feb 10 Javascript
实例分析vue循环列表动态数据的处理方法
Sep 28 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
《忧国的莫里亚蒂》先导宣传图与STAFF公开
2020/03/04 日漫
做了CDN获取用户真实IP的函数代码(PHP与Asp设置方式)
2013/04/13 PHP
php通过session防url攻击方法
2014/12/10 PHP
为超链接加上disabled后的故事
2010/12/10 Javascript
获取元素距离浏览器周边的位置的方法getBoundingClientRect
2013/04/17 Javascript
IE6-IE9中tbody的innerHTML不能赋值的解决方法
2014/06/05 Javascript
jquery实现html页面 div 假分页有原理有代码
2014/09/06 Javascript
JavaScript实现穷举排列(permutation)算法谜题解答
2014/12/29 Javascript
js实现鼠标经过时图片滚动停止的方法
2015/02/16 Javascript
javascript生成大小写字母
2015/07/03 Javascript
JavaScript实现阿拉伯数字和中文数字互相转换
2016/06/12 Javascript
JS实现的二叉树算法完整实例
2017/04/06 Javascript
vue自定义指令directive实例详解
2018/01/17 Javascript
一篇不错的Python入门教程
2007/02/08 Python
Python中字典和集合学习小结
2017/07/07 Python
在Windows中设置Python环境变量的实例讲解
2018/04/28 Python
详解python中的json和字典dict
2018/06/22 Python
python实现飞机大战游戏(pygame版)
2020/10/26 Python
Python获取、格式化当前时间日期的方法
2020/02/10 Python
python使用docx模块读写docx文件的方法与docx模块常用方法详解
2020/02/17 Python
关于Python字符串显示u...的解决方式
2020/03/06 Python
python实现最短路径的实例方法
2020/07/19 Python
html5 Canvas画图教程(4)—未闭合的路径及渐变色的填充方法
2013/01/09 HTML / CSS
销售所有的狗狗产品:Dog.com
2016/10/13 全球购物
Otticanet澳大利亚:最顶尖的世界名牌眼镜, 能得到打折季的价格
2018/08/23 全球购物
工程造价与财务管理专业应届生求职信
2013/10/06 职场文书
会计实习期自我鉴定
2013/10/06 职场文书
小学门卫岗位职责
2013/12/17 职场文书
获奖的大学生创业计划书
2014/01/05 职场文书
运动会广播稿400字
2014/01/25 职场文书
公司年会策划方案
2014/05/17 职场文书
高中班长竞选稿
2015/11/20 职场文书
护士岗前培训心得体会
2016/01/08 职场文书
我的暑假生活作文(五年级)范文
2019/08/07 职场文书
asyncio异步编程之Task对象详解
2022/03/13 Python
Python使用openpyxl模块处理Excel文件
2022/06/05 Python