Динамически распределять строки и столбцы сетки для изображения на основе фактической высоты и ширины файла изображения (React)

#javascript #css #reactjs

#javascript #css #reactjs

Вопрос:

У меня есть конкретное требование, которое заключается в динамическом определении количества строк и столбцов, необходимых для охвата, на основе высоты изображения. Я попробовал несколько способов, последний из которых находится в конце вопроса.

Вот текущий код, который нуждается в предложениях

HTML

 <div className="grid">
    {
     pictures.map((pic,i)=>{
      return(
        <div key={pic.name i} className="pic-container" 
         style={{ 
             gridRowStart: pic.row, gridColumnStart:pic.col, 
             // Need to put the height amp; width of each image in the array 
             // in the following place to span dynamically
             gridRowEnd: HEIGHT/50 , gridColumnEnd:8*(WIDTH/1400)}}>
         <div>
            <img src={`/pictures/${pic.name}.png`} className="pic"/>
            <div className="pic-name">{pic.name}</div>
         </div>
        </div>
      );
    }
</div>

 

CSS

 .grid{
  display: grid;
  grid-template-rows: repeat(99, 50px);
  grid-template-columns: repeat(8, 1fr);
  max-width: 1400px;
  gap: 0px;
  position: relative;
  z-index: 2;
}
.pic-container{
  width: 100%;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
}
.pic-container > div{
  display: block;
  width:100%;
  height:100%;
}

.pic{
  max-width: 100%;
  max-height: 100%;
  height: 100%;
  object-fit: contain;
}

 

Последнее, что я пробовал:

 const [width,setWidth] = useState(null);
const [height,setHeight] = useState(null);
.
..
...
pictures.map((pic,i)=>{
  const getDim = (e) =>{
    setWidth(e.target.offsetWidth);
    setHeight(e.target.offsetHeight);
  }
  return(
    <div key={'' pic.name i} className="pic-container" 
     style={{gridArea:`${pic.row} / ${pic.col} / span ${Math.ceil(height/50)} / span ${Math.ceil(8*(width/1400))`}}>
      <div>
        <img onLoad={getDim} className="pic" src={`/pictures/${pic.name}.png`}/>
        <div className="pic-name">{pic.name}</div>
      </div>
    </div>
  )
})
 

Идея предыдущего решения заключается в том, что каждый раз, когда мы получаем новое изображение, состояние ширины и высоты будет обновляться с учетом новых размеров изображения, а затем будет применено к промежутку. Следующее изображение обновит ширину и высоту, а затем применит их к своему диапазону и так далее и тому подобное. Но это не сработало.

Ответ №1:

Я надеюсь, что это может вам помочь.

Демонстрация песочницы здесь

Компонент списка изображений:

     const ImageList = (props) => {
    
    const images = props.images.map((image) => {
        return <ImageCard key={image.id} image={image} />
    });
   return <div className="image-list">{images}</div>
 

Список изображений Css

 .image-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    grid-gap:0 10px;
    grid-auto-rows: 10px;
}

.image-list img {
    width: 250px;
 }
 

Компонент ImageCard:

 class ImageCard extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            spans : 0
        }
        this.imageRef = React.createRef();
    }    

    componentDidMount() {
         this.imageRef.current.addEventListener('load', this.setSpans);

    }

    setSpans = () => {
        const height = this.imageRef.current.clientHeight;

        const spans = Math.ceil(height / 10);

        this.setState({spans});
    }

    render() {
        const {description, urls} = this.props.image;
        return (
            <div style={{gridRowEnd: `span ${this.state.spans}`}}>
                <img ref={this.imageRef} src={urls.regular} alt={description} />
            </div>
        );
    }
 

Комментарии:

1. @AnasNabulsi если вы используете это решение, не забудьте удалить прослушиватель событий из компонента в функции componentDidUnmount, иначе у вас возникнут проблемы с утечкой памяти!

2. Спасибо, Саад, ваше решение дало мне некоторое представление. Разделение контейнера изображения как компонента и использование ref с useEffect (componentDidMount) для получения высоты помогло мне лучше решить эту проблему, хотя мне пришлось внести коррективы в стиль, чтобы соответствовать моим требованиям.