简体   繁体   中英

Span grid rows and columns dynamically for an image based on the image file actual height and width ( React )

I have a specific requirement which is to dynamically determine the number of rows & columns needed to be spanned based on image height. I have tried couple of ways, latest one of them is at the end of the question.

Here is the current code that needs suggestions

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 & 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;
}

Latest that I have tried:

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

The idea behind the previous solution is that everytime we get a new image the state of width and height will get updated with the new image dimensions and then will be applied on the span. Next image will update the width and height and then have them applied on its span and so on so forth. But that didn't work.

I hope this maybe help you.

Sandbox demo here

Image List Component:

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

Image List 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 component:

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>
        );
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM