溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何使用react-virtualized實(shí)現(xiàn)圖片動態(tài)高度長列表

發(fā)布時間:2021-05-28 10:26:10 來源:億速云 閱讀:505 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下如何使用react-virtualized實(shí)現(xiàn)圖片動態(tài)高度長列表,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

虛擬列表是一種根據(jù)滾動容器元素的可視區(qū)域來渲染長列表數(shù)據(jù)中某一個部分?jǐn)?shù)據(jù)的技術(shù)。虛擬列表是對長列表場景一種常見的優(yōu)化,畢竟很少有人在列表中渲染上百個子元素,只需要在滾動條橫向或縱向滾動時將可視區(qū)域內(nèi)的元素渲染出即可。

開發(fā)中遇到的問題

1.長列表中的圖片要保持原圖片相同的比例,那縱向滾動在寬度不變的情況下,每張圖片的高度就是動態(tài)的,當(dāng)該列表項(xiàng)高度發(fā)生了變化,會影響該列表項(xiàng)及其之后所有列表項(xiàng)的位置信息。

2.圖片width,height必須在圖片加載完成后才能獲得.

解決方案

我們使用react-virtualized中l(wèi)ist組件,官方給出的例子

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實(shí)現(xiàn)圖片動態(tài)高度長列表

其中rowHeight是每一行的高度,可以傳入固定高度也可以傳入function。每次子元素高度改變需要調(diào)用recomputeRowHeights方法,指定索引后重新計(jì)算行高度和偏移量。

具體實(shí)現(xiàn)

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} />
}

先寫一個獲取圖片高度的組件,通過定時循環(huán)檢測獲取并計(jì)算出高度傳給父組件。

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方法收集所有圖片的高度,并在每一次高度改變調(diào)用List組件的recomputeRowHeights方法通知組件重新計(jì)算高度和偏移。到這里基本已經(jīng)解決遇到的問題。

實(shí)際效果

如何使用react-virtualized實(shí)現(xiàn)圖片動態(tài)高度長列表

目前只是使用react-virtualized來完成圖片長列表實(shí)現(xiàn),具體react-virtualized內(nèi)部實(shí)現(xiàn)還需要進(jìn)一步研究。

看完了這篇文章,相信你對“如何使用react-virtualized實(shí)現(xiàn)圖片動態(tài)高度長列表”有了一定的了解,如果想了解更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI