使用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 相关文章推荐
Jquery Ajax学习实例6 向WebService发出请求,返回DataSet(XML) 异步调用
Mar 18 Javascript
JS小功能(offsetLeft实现图片滚动效果)实例代码
Nov 28 Javascript
jquery和ajax的关系详细介绍
Nov 29 Javascript
jQuery学习总结之jQuery事件
Jun 30 Javascript
Angular2  NgModule 模块详解
Oct 19 Javascript
基于JS实现checkbox全选功能实例代码
Oct 31 Javascript
jquery实现转盘抽奖功能
Jan 06 Javascript
js实现导航栏中英文切换效果
Jan 16 Javascript
微信小程序之picker日期和时间选择器
Feb 09 Javascript
angular select 默认值设置方法
Jun 23 Javascript
微信小程序实现长按删除图片的示例
May 18 Javascript
nuxt 页面路由配置,主页轮播组件开发操作
Nov 05 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
排序算法之PHP版快速排序、冒泡排序
2014/04/09 PHP
CodeIgniter连贯操作的底层原理分析
2016/05/17 PHP
PHP排序算法之直接插入排序(Straight Insertion Sort)实例分析
2018/04/20 PHP
探讨jQuery的ajax使用场景(c#)
2013/12/03 Javascript
JavaScript使用HTML5的window.postMessage实现跨域通信例子
2014/04/11 Javascript
node.js中使用socket.io制作命名空间
2014/12/15 Javascript
javascript实现base64 md5 sha1 密码加密
2015/09/09 Javascript
jQuery控制文本框只能输入数字和字母及使用方法
2016/05/26 Javascript
jQuery.parseHTML() 函数详解
2017/01/09 Javascript
详解Javascript百度地图接口开发文档中的类和方法
2017/02/07 Javascript
Nodejs+angularjs结合multiparty实现多图片上传的示例代码
2017/09/29 NodeJs
JavaScript实现京东购物放大镜和选项卡效果的方法分析
2018/07/05 Javascript
Vue.extend 编程式插入组件的实现
2019/11/18 Javascript
Vue.js获取手机系统型号、版本、浏览器类型的示例代码
2020/05/10 Javascript
vue+iview实现分页及查询功能
2020/11/17 Vue.js
[38:44]DOTA2上海特级锦标赛A组小组赛#2 Secret VS CDEC第二局
2016/02/25 DOTA
python远程登录代码
2008/04/29 Python
python使用rsa加密算法模块模拟新浪微博登录
2014/01/22 Python
python3 flask实现文件上传功能
2020/03/20 Python
python爬虫模块URL管理器模块用法解析
2020/02/03 Python
Python Selenium 设置元素等待的三种方式
2020/03/18 Python
基于OpenCV的路面质量检测的实现
2020/11/04 Python
发现两个有趣的CSS3动画效果
2013/08/14 HTML / CSS
HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题
2021/01/19 HTML / CSS
欧舒丹比利时官网:L’OCCITANE比利时
2017/04/25 全球购物
GANT英国官方网上商店:甘特衬衫
2018/02/06 全球购物
英国DIY汽车维修配件网站:DIY Car Service Parts
2019/08/30 全球购物
瑞典在互联网上最大的宠物商店:Animail
2020/10/31 全球购物
CHARLES & KEITH加拿大官网:新加坡时尚品牌
2020/03/26 全球购物
通用C#笔试题附答案
2016/11/26 面试题
2014年初一班主任工作总结
2014/11/08 职场文书
初中生思想道德自我评价
2015/03/09 职场文书
求职信:会计求职的写作技巧
2019/04/24 职场文书
2019教师的学习计划
2019/06/25 职场文书
PostgreSQL存储过程实用脚本(二):创建函数入门
2021/04/05 PostgreSQL
一篇带你入门Java垃圾回收器
2021/06/16 Java/Android