Переключение между сеткой изображений и слайдером изображений с одним массивом изображений в хуках реакции - PullRequest
0 голосов
/ 18 июня 2020

Я создаю проект с Next js, React и использую Sanity в качестве CMS.

Одним из основных компонентов будет галерея изображений, которые, когда вы нажимаете на изображение, вы будете открыть галерею слайдеров изображений. Изображения представляют собой массив, переданный из CMS.

Это примерно зависит от того, как работает этот веб-сайт .. https://www.garrodkirkwood.com/projects/

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

В ЧЕМ НУЖНА ПОМОЩЬ ...

Мне нужно найти способ передать индекс нажатой кнопки изображение в прослушиватель событий, чтобы при нажатии на изображение вы открывали слайд-шоу на ТАКОМ ИЗОБРАЖЕНИИ.

Я действительно надеюсь, что это имеет смысл.

Затем пользователь выйдет из слайд-шоу, щелкнув на 'показать эскизы'

import React, { useState, useEffect, useRef } from "react";
import { css, jsx } from "@emotion/core";
import ImageSliderContent from "./ImageSliderContent";
import styles from "./ImageGrid.module.css";
import ImageGrid from "./ImageGrid";
import ImageSlide from "./ImageSlide";
import Arrow from "./Arrow";
import Dots from "./Dots";
import imageUrlBuilder from "@sanity/image-url";
import client from "../../client";

const builder = imageUrlBuilder(client);

const LocationsImageGallery = (props) => {
  const { caption, image } = props;

  const images = props.image;

  const [state, setState] = useState({
    translate: 0,
    transition: 0.45,
    activeSlide: 0,
  });

  const [showSlider, setShowSlider] = useState(false);

  const { translate, transition, activeSlide, _slides } = state;

  const size = useWindowSize();
  const transitionRef = useRef();

  function useWindowSize() {
    const isClient = typeof window === "object";

    function getSize() {
      return {
        width: isClient ? window.innerWidth : undefined,
      };
    }

    const [windowSize, setWindowSize] = useState(getSize);

    useEffect(() => {
      if (!isClient) {
        return false;
      }

      function handleResize() {
        setWindowSize(getSize());
      }

      window.addEventListener("resize", handleResize);
      return () => window.removeEventListener("resize", handleResize);
    }, []);

    return windowSize;
  }

  const nextSlide = () => {
    if (activeSlide === images.length - 1) {
      return setState({
        ...state,
        translate: 0,
        activeSlide: 0,
      });
    }

    setState({
      ...state,
      activeSlide: activeSlide + 1,
      translate: (activeSlide + 1) * size.width,
    });
  };

  const prevSlide = () => {
    if (activeSlide === 0) {
      return setState({
        ...state,
        translate: (images.length - 1) * size.width,
        activeSlide: images.length - 1,
      });
    }

    setState({
      ...state,
      activeSlide: activeSlide - 1,
      translate: (activeSlide - 1) * size.width,
    });
  };

  const show = () => {
    setShowSlider(true);
  };

  const hide = () => {
    setShowSlider(false);
  };

  return (
    <div className={styles.root}>
      <div className={styles.imageGridContainer}>
        {images.map((image, index) => (
          <div className={styles.imageContainer} onClick={show}>
            <img
              src={builder.image(image).auto("format").width(2000).url()}
              className={styles.image}
              alt={image.caption}
              key={index}
            />
            <p className={styles.caption}>{image.caption}</p>
          </div>
        ))}
      </div>

      {showSlider && (
        <div className={styles.imageGalleryContainer}>
          <div css={ImageSliderCSS}>
            <ImageSliderContent
              translate={translate}
              transition={transition}
              width={size.width * images.length}
            >
              {images.map((image, index) => (
                <ImageSlide
                  key={image + index}
                  content={builder.image(image).auto("format").width(2000).url()}
                ></ImageSlide>
              ))}
            </ImageSliderContent>
            <Arrow direction="left" handleClick={prevSlide} />
            <Arrow direction="right" handleClick={nextSlide} />
            <Dots slides={images} activeSlide={activeSlide} />
          </div>
          <a href="" onClick={hide}>
            Show Thumbnails
          </a>
        </div>
      )}
    </div>
  );
};

const ImageSliderCSS = css`
  position: relative;
  height: 500px;
  width: 750px;
  margin: 0 auto;
  overflow: hidden;
`;
export default LocationsImageGallery;

ОБНОВЛЕНО С ИНДЕКСОМ ПРОХОДА ДЛЯ ЩЕЛЧКА СОБЫТИЯ

import React, { useState, useEffect, useRef } from "react";
import { css, jsx } from "@emotion/core";
import ImageSliderContent from "./ImageSliderContent";
import styles from "./LocationsImageGallery.module.css";
import ImageGrid from "./ImageGrid";
import ImageSlide from "./ImageSlide";
import Arrow from "./Arrow";
import Dots from "./Dots";
import imageUrlBuilder from "@sanity/image-url";
import client from "../../client";

const builder = imageUrlBuilder(client);

const LocationsImageGallery = (props) => {
  const { caption, image } = props;

  const images = props.image;

  const [state, setState] = useState({
    translate: 0,
    transition: 0.45,
    activeSlide: 0,
  });

  const [showSlider, setShowSlider] = useState(false);
  const [showGrid, setShowGrid] = useState(true);

  const { translate, transition, activeSlide, _slides } = state;

  const size = useWindowSize();
  const transitionRef = useRef();

  function useWindowSize() {
    const isClient = typeof window === "object";

    function getSize() {
      return {
        width: isClient ? window.innerWidth : undefined,
      };
    }

    const [windowSize, setWindowSize] = useState(getSize);

    useEffect(() => {
      if (!isClient) {
        return false;
      }

      function handleResize() {
        setWindowSize(getSize());
      }

      window.addEventListener("resize", handleResize);
      return () => window.removeEventListener("resize", handleResize);
    }, []);

    return windowSize;
  }

  const nextSlide = () => {
    if (activeSlide === images.length - 1) {
      return setState({
        ...state,
        translate: 0,
        activeSlide: 0,
      });
    }

    setState({
      ...state,
      activeSlide: activeSlide + 1,
      translate: (activeSlide + 1) * size.width,
    });
  };

  const prevSlide = () => {
    if (activeSlide === 0) {
      return setState({
        ...state,
        translate: (images.length - 1) * size.width,
        activeSlide: images.length - 1,
      });
    }

    setState({
      ...state,
      activeSlide: activeSlide - 1,
      translate: (activeSlide - 1) * size.width,
    });
  };

  const show = (index) => {
    setShowGrid(false);
    setShowSlider(true);
    setState({ activeSlide: index });
  };

  const hide = () => {
    setShowSlider(false);
    setShowGrid(true);
  };

  return (
    <div className={styles.root}>
      <div className={styles.header}>
        <a href="/locations">X</a>
      </div>
      {showGrid && (
        <div className={styles.imageGrid}>
          <div className={styles.imageGridContainer}>
            {images.map((image, index, caption) => (
              <div className={styles.imageContainer} onClick={() => show(index)}>
                <img
                  src={builder.image(image).auto("format").width(2000).url()}
                  className={styles.image}
                  alt={image.caption}
                  key={index}
                />
                <p className={styles.caption}>{image.caption}</p>
              </div>
            ))}
          </div>
        </div>
      )}

      {showSlider && (
        <div className={styles.imageGalleryContainer}>
          <div className={styles.imageSlider}>
            <ImageSliderContent
              translate={translate}
              transition={transition}
              width={size.width * images.length}
            >
              {images.map((image, index, caption) => (
                <>
                  <ImageSlide
                    key={image + index}
                    content={builder.image(image).auto("format").url()}
                  ></ImageSlide>
                </>
              ))}
            </ImageSliderContent>
            <Arrow direction="left" handleClick={prevSlide} />
            <Arrow direction="right" handleClick={nextSlide} />
          </div>
          <div className={styles.infoBar}>
            <p className={styles.infoCaption}>
              Locations / <span>{image.caption}</span>
            </p>
            <a href="" onClick={hide} className={styles.infoThumbnails}>
              Show Thumbnails
            </a>
          </div>
        </div>
      )}
    </div>
  );
};

export default LocationsImageGallery;

Эта версия, похоже, не обновляет состояние, console.log activeSlide и состояние ...

LocationsImageGallery.js?0692:94 {activeSlide: 8, state: {…}} activeSlide: 8 state: activeSlide: 0 transition: 0.45 translate: 0 proto: Object proto: Object

1 Ответ

0 голосов
/ 18 июня 2020

Вы можете изменить функцию показа, чтобы она принимала индекс слайда в качестве аргумента:

  const show = (index) => {
    // set activeSlide accordingly
    setState(...)
    setShowSlider(true);
  }

Затем в функции onClick передайте индекс:

onClick={() => show(index)}

Если бы я был вы, я мог бы удалить состояние showSlider и использовать activeSlide: -1 или activeSlide: null для обозначения того, что слайдер не отображается.

...