使用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 自动安装exe程序
Nov 30 Javascript
window.location和document.location的区别分析
Dec 23 Javascript
jQuery 页面载入进度条实现代码
Feb 08 Javascript
经过绑定元素时会多次触发mouseover和mouseout事件
Feb 28 Javascript
input框中的name和id的区别
Nov 16 Javascript
jquery 禁止鼠标右键并监听右键事件
Apr 27 jQuery
JavaScript实现简单的树形菜单效果
Jun 23 Javascript
Javascript实现跨域后台设置拦截的方法详解
Aug 04 Javascript
解决VUE框架 导致绑定事件的阻止冒泡失效问题
Feb 24 Javascript
通过JQuery,JQueryUI和Jsplumb实现拖拽模块
Jun 18 jQuery
Vue使用vue-recoure + http-proxy-middleware + vuex配合promise实现基本的跨域请求封装
Oct 21 Javascript
vue3引入highlight.js进行代码高亮的方法实例
Apr 08 Vue.js
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
dedecms模版制作使用方法
2007/04/03 PHP
mysql 中InnoDB和MyISAM的区别分析小结
2008/04/15 PHP
免费的ip数据库淘宝IP地址库简介和PHP调用实例
2014/04/08 PHP
浅谈使用 PHP 进行手机 APP 开发(API 接口开发)
2014/08/11 PHP
php数组比较实现查找连续数的方法
2015/07/29 PHP
jQuery textarea的长度进行验证
2009/05/06 Javascript
javascript新建标签,判断键盘输入,以及判断焦点(示例代码)
2013/11/25 Javascript
js/jquery解析json和数组格式的方法详解
2014/01/09 Javascript
基于JavaScript将表单序列化类型的数据转化成对象的处理(允许对象中包含对象)
2015/12/28 Javascript
实例讲解JavaScript的Backbone.js框架中的View视图
2016/05/05 Javascript
JS中的hasOwnProperty()、propertyIsEnumerable()和isPrototypeOf()
2016/08/11 Javascript
关于List.ToArray()方法的效率测试
2016/09/30 Javascript
详解利用 Express 托管静态文件的方法
2017/09/18 Javascript
React通过父组件传递类名给子组件的实现方法
2017/11/13 Javascript
angularjs 的数据绑定实现原理
2018/07/02 Javascript
Django+vue跨域问题解决的详细步骤
2019/01/20 Javascript
vant 时间选择器--开始时间和结束时间实例
2020/11/04 Javascript
Python基于回溯法子集树模板解决野人与传教士问题示例
2017/09/11 Python
Python3计算三角形的面积代码
2017/12/18 Python
python判断输入日期为第几天的实例
2018/11/13 Python
python for循环输入一个矩阵的实例
2018/11/14 Python
python中强大的format函数实例详解
2018/12/05 Python
Python numpy线性代数用法实例解析
2019/11/15 Python
Jmeter HTTPS接口测试证书导入过程图解
2020/07/22 Python
Python压缩模块zipfile实现原理及用法解析
2020/08/14 Python
Pycharm无法打开双击没反应的问题及解决方案
2020/08/17 Python
python 根据列表批量下载网易云音乐的免费音乐
2020/12/03 Python
CSS3中动画属性transform、transition和animation属性的区别
2016/09/25 HTML / CSS
可持续木材、生态和铝制太阳镜:Proof Eyewear
2019/07/24 全球购物
致1500米运动员广播稿
2014/02/07 职场文书
校庆标语集锦
2014/06/25 职场文书
本科应届生求职信
2014/08/05 职场文书
2014年自愿离婚协议书范本
2014/09/25 职场文书
2015年教师党员自我评价材料
2015/03/04 职场文书
2016年基层党组织公开承诺书
2016/03/25 职场文书
Python实现拼音转换
2021/06/07 Python