ReactJS 中的图像模态与幻灯片使用 JavaScript

Image modal in ReactJS with slideshow using JavaScript

我正在尝试在 React 应用程序中使用此图片灯箱:

https://www.w3schools.com/howto/howto_js_lightbox.asp

这是代码沙箱link什么都试过了

https://codesandbox.io/s/reactjs-practice-vbxwt

图像模态对我来说效果很好。但是当我尝试实现 slider.I 想要为每个列表实现滑块时,它似乎不起作用。我正在从后端获取图像数据。

以下是我获取所有图像数据的方式:

{
    "results": [{
        "data": [{
            "id": "f06f2cdf-1bb8-4388-a655-4e916a2703ce",
            "visitRequirementList": [{
                "imageName": "dining pic 1",
                "imagePath": "visitImageDirectory/0297b1ef-644b-45fc-9760-4e5693f54ac0.png",
            }, {
                "imageName": "dining pic 2",
                "imagePath": "visitImageDirectory/1b4915c1-733a-4bdb-a8d7-59ce3a095d44.png",
            }]
        }, {
            "id": "ce059d7a-d3d4-462c-a90f-62be13f24a29",
            "visitRequirementList": [{
                "imageName": "bedroom pic 1",
                "imagePath": "visitImageDirectory/64960b86-f9bf-4de9-816f-f27487245c53.png",
            }]
        }]
    }],
    "message": "data Found",
    "status": "success"
}

这是我的 render 显示图像的方法:

import React, { Component } from 'react';

export default class extends Component {
    state = {
        showModal: false,
        caption: '',
        modalSrc: '',
        ioImageListing: [],

        // ...rest of the state
    };
    componentDidMount() {
        this.getAllProjectRequirementImageList();
    }
    getAllProjectRequirementImageList = () => {
        axios.get(this.state.apiUrl+'/api/v1/visitRequirement/getAllByProjectId', {
            params: {   projectId: this.state.projectId }
        }).then((response) => {
            console.log("get with list ImageData",response.data.data);
            this.setState({ ioImageListing: response.data.data  });
        }).catch((error)=>{  console.log("error",error); this.setState({ ioImageListing: []  });   });
    }



    render() {
        return (
            <div>
                <div style={{}}>
                    {this.state.ioImageListing.map((io, key) =>
                        <Grid container spacing={24}>
                            {io.visitRequirementList.map((pic, key) => [
                                <Grid style={{position: 'relative'}} item xs={3} key={key}>
                                <span key={key}>
                                    <img
                                        src={this.state.apiUrl + '/api/v1/visitImageRequirementInfo/getImageByImagePathId?imagePath=' + pic.imagePath}
                                        onClick={() => {
                                            this.setState({
                                                showModal: true,
                                                caption: `${pic.imageName}`,
                                                slideIndex: `${io.visitRequirementList.length}`,
                                                modalSrc: `${this.state.apiUrl}/api/v1/visitImageRequirementInfo/getImageByImagePathId?imagePath=${pic.imagePath}`,
                                                count: `${key}`
                                            });
                                        }}
                                    />
                                </span>
                                </Grid>
                            ])}
                        </Grid>
                    )}
                </div>
                <div id="myModal" className="modal" style={{display: this.state.showModal ? 'block' : 'none'}}>
                    <div>
                        <span className="close" onClick={() => this.setState({showModal: false})}>&times;</span>
                        <div className="mySlides"><img className="modal-content" id="img01" src={this.state.modalSrc}/>
                        </div>
                        <a className="prev" onClick={() => {
                            this.plusSlides(-1)
                        }}>&#10094;</a>
                        <a className="next" onClick={() => {
                            this.plusSlides(1)
                        }}>&#10095;</a>
                    </div>
                </div>
            </div>
        );
    }
}

这是我为显示滑块而编写的函数:

    plusSlides = (n) => {
        var slideIndex=parseFloat(this.state.count);
        slideIndex=slideIndex+n
        this.setState({ count: slideIndex  });

        this.showSlides(slideIndex, n);
    }

  showSlides(slideIndex,n) {
        var i;
        var slides = document.getElementsByClassName("mySlides");
        if (n > slides.length) {slideIndex = 1}
        if (n < 1) {slideIndex = slides.length}
        for (i = 1; i < slides.length; i++) {
            slides[i].style.display = "none";
        }
        slides[slideIndex-1].style.display = "block";
    }

当图像模态打开时,我想通过单击下一个和上一个按钮将其变成幻灯片。我做错了什么?

您需要将图像保存在一个数组中:将这些图像保存到状态中,然后将 "mySlides" 中的 img 更改为如下所示:

/** -- snip -- **/
// Inside of "mySlides" div
<img 
    className="modal-content" 
    id="img01" 
    src={this.state.images[this.state.count]}
/>

首先,你没有以正确的方式使用 React。函数 showSlides 直接使用 DOM 操作。始终避免直接操作 DOM,而是将 state 更新为所需的值,让 React 为您处理 DOM。

话虽如此,让我解释一下您的滑块如何通过仅更新 state 以反应方式工作。到目前为止,您已经设法使模态工作。滑块逻辑如下(codesandbox link):

你的imageListData是一个list of list。为清楚起见,我将外部列表称为 section

1 - 单击任何图像时,使用以下数据更新状态:

showModal // to toggle the visibility of modal
caption // caption for current image
modalSrc // current image source
sectionIndex // current index of outer list
imageIndex // index of current image
currentSectionLength // outer list, i.e. section length

2 - 单击 NextPrevious 按钮时,我们将仅更新步骤 1 中提到的状态,滑块将起作用。唯一要考虑的是用正确的值更新状态的逻辑。我将尝试通过评论来解释它。所有逻辑都在 plusSlides 函数中。

plusSlides = n => {
    const { ioImageListing, imageIndex, sectionIndex, currentSectionLength } = this.state; // extract all the current values from the state

    const nextIndex = imageIndex + n; // add or subtract 1 to get nextIndex. This is temporary. We will use this to determine next image on the slider.
    const numberOfSections = ioImageListing.length; // count of number of outer list.

    if (nextIndex < 0 && sectionIndex === 0) {
      // this means we are at the 1st image of 1st section. Hence no more left navigation, and the function returns. No more execution.
      alert("NO MORE LEFT IMAGE");
      return;
    }

    if (sectionIndex === numberOfSections - 1 && nextIndex > ioImageListing[numberOfSections - 1].visitRequirementList.length - 1) {
      // this condition says we are at the last image of last section. Hence no more right navigation, and the function returns. No more execution.
      alert("NO MORE RIGHT IMAGE");
      return;
    }

    let nextImage, nextImageIndex, nextSectionIndex, nextSectionLength; // these variables will hold the value for next image to be shown determined by the following logic

    if (nextIndex >= 0 && nextIndex < currentSectionLength) {
      // if the nextIndex is >=0 and less than the length of currentSectionLength, it means our next/previous image is in the same section. So we only need to update nextImage data whereas section data remains same
      nextImage = ioImageListing[sectionIndex].visitRequirementList[nextIndex];
      nextImageIndex = nextIndex;
      nextSectionIndex = sectionIndex;
      nextSectionLength = currentSectionLength;
    } else if (nextIndex < 0) {
      // if the nextIndex is less than 0, it means our previous image is in the previous section and it has to be the last image of previous section. So we update both nextImage data and section data accordingly.
      nextImage = ioImageListing[sectionIndex - 1].visitRequirementList[ioImageListing[sectionIndex - 1].visitRequirementList.length - 1];
      nextImageIndex = ioImageListing[sectionIndex - 1].visitRequirementList.length - 1;
      nextSectionIndex = sectionIndex - 1;
      nextSectionLength = ioImageListing[sectionIndex - 1].visitRequirementList.length
    } else {
      // atlast if the nextIndex >= currentSectionLength, it means our next image is in the next section and it has to be the first image of next section. So we update both nextImage data and section data accordingly.
      nextImage = ioImageListing[sectionIndex + 1].visitRequirementList[0];
      nextImageIndex = 0;
      nextSectionIndex = sectionIndex + 1;
      nextSectionLength = ioImageListing[sectionIndex + 1].visitRequirementList.length;
    }

    // finally we update the state with current next values, and the slider works as expected.
    this.setState({
      caption: nextImage.imageName,
      modalSrc: nextImage.imagePath,
      imageIndex:nextImageIndex,
      sectionIndex: nextSectionIndex,
      currentSectionLength:nextSectionLength
    });
  }

希望对您有所帮助。如果有任何疑问,请告诉我。工作代码在 link

中可用