YIZHUANG / react-multi-carousel

A lightweight production-ready Carousel that rocks supports multiple items and server-side rendering with no dependency. Bundle size 2kb.
MIT License
1.3k stars 292 forks source link

If there are a total of 3 slide images, can't I adjust the scale and opacity of only the images on both sides? #389

Open brgndyy opened 1 year ago

brgndyy commented 1 year ago

Looking at other issues classname-of-carousel-item:not(.classname-of-active-item)

It is said that css was manipulated in this way, and css can be fed to each item in the document,

If you look at the code, each item does not exist because it is being sprinkled with the map function. How can I feed the opacity and scale properties only to the side items?


export default function SliderImage() {
  const [data, setData] = useState<ImageData[]>();

  const fetchData = async () => {
    const res = await fetch(`https://picsum.photos/v2/list?limit=4`);
    const data = await res.json();
    setData(data);
  };

  useEffect(() => {
    fetchData();
  }, []);

  useEffect(() => {
    console.log(data);
  }, [data]); 

  return (
    <>
      {data ? (
        <Carousel
          responsive={responsive}
          infinite={true}
          autoPlay={true}
          autoPlaySpeed={3000}
          customTransition="all 0.5s"
          transitionDuration={500}
          containerClass="carousel-container"
          dotListClass="custom-dot-list-style"
          itemClass="carousel-item-padding-40-px"
          arrows={false}
        >
          {data.map((item) => {
            return (
              <div key={item.id} className={classes.carousel_item}>
                <Image
                  src={item.download_url}
                  width={300}
                  height={500}
                  alt="image"
                />
              </div>
            );
          })}
        </Carousel>
      ) : (
        <p>Loading...</p>
      )}
    </>
  );
}
brgndyy commented 1 year ago

please help me😭😭😭😭😭😭

WesleyMcGhee1 commented 1 year ago

What you might have to do is create a seprate class that take the image and then detects if it's the current index or not.

So it could be something like this.

const [index, setIndex] = useState(0);

const handleCarouselChange = (nextSlide, currentSlide) => {
  const isNext = nextSlide > currentSlide;

  if (isNext && index === data.length - 1) {
    setIndex(0)
  } else if (!isNext && Index === 0) {
    setIndex(data.length - 1);
  } else {
    isNext ?
      ? setIndex(index + 1)
      : setIndex(index - 1);
  }
}

<Carousel beforeChange={(nextSlide, { currentSlide }) => {
  handleCarouselChange(nextSlide, currentSlide);
}}>
  {data.map((item, idx) => {
      <Image 
        src={item.download_url}
        width={300}
        height={500}
        alt="image"
       className={ idx === index ? "activeImage" : "inactiveImage"}
      />
  })}
</Carousel>

I haven't tested this but just a proposed solution.

moiguitarrock commented 3 weeks ago

What you might have to do is create a seprate class that take the image and then detects if it's the current index or not.

So it could be something like this.

const [index, setIndex] = useState(0);

const handleCarouselChange = (nextSlide, currentSlide) => {
  const isNext = nextSlide > currentSlide;

  if (isNext && index === data.length - 1) {
    setIndex(0)
  } else if (!isNext && Index === 0) {
    setIndex(data.length - 1);
  } else {
    isNext ?
      ? setIndex(index + 1)
      : setIndex(index - 1);
  }
}

<Carousel beforeChange={(nextSlide, { currentSlide }) => {
  handleCarouselChange(nextSlide, currentSlide);
}}>
  {data.map((item, idx) => {
      <Image 
        src={item.download_url}
        width={300}
        height={500}
        alt="image"
       className={ idx === index ? "activeImage" : "inactiveImage"}
      />
  })}
</Carousel>

I haven't tested this but just a proposed solution.

Nice idea, made it inspired in your code, needed to handle some more scenarios as users can click on any dot so the slides can change by higher increments.

"use client";
import Carousel from "react-multi-carousel";
import "react-multi-carousel/lib/styles.css";

import React, { useState } from "react";

function CustomCarousel({ renderItems }: { renderItems: React.ReactNode[] }) {
  const [index, setIndex] = useState(1);
  const responsive = {
    superLargeDesktop: {
      breakpoint: { max: 4000, min: 3000 },
      partialVisibilityGutter: 40,
      items: 3,
    },
    desktop: {
      breakpoint: { max: 3000, min: 1024 },
      partialVisibilityGutter: 40,
      items: 3,
    },
    tablet: {
      breakpoint: { max: 1024, min: 464 },
      partialVisibilityGutter: 40,
      items: 2,
    },
    mobile: {
      breakpoint: { max: 464, min: 0 },
      partialVisibilityGutter: 40,

      items: 1,
    },
  };

  const handleBeforeChange = (
    nextSlide: number,
    currentSlide: number,
    slidesToShow: number
  ) => {
    const isNext = nextSlide > currentSlide;

    const middleIndex = Math.floor(slidesToShow / 2);

    let diff = isNext ? nextSlide - currentSlide : currentSlide - nextSlide;

    if (nextSlide === currentSlide) {
      return;
    }
    if (isNext && index === renderItems.length - middleIndex) {
      setIndex(0);
    } else if (!isNext && index === 0 && diff === 1) {
      setIndex(renderItems.length - middleIndex);
    } else if (diff === 1) {
      setIndex((currentSlide) =>
        isNext ? currentSlide + 1 : currentSlide - 1
      );
    } else {
      setIndex((currentSlide) => {
        if (isNext) {
          const newIndex = currentSlide + diff;
          return newIndex >= renderItems.length
            ? newIndex % renderItems.length
            : newIndex;
        } else {
          const newIndex = currentSlide - diff;
          return newIndex < 0 ? renderItems.length + newIndex : newIndex;
        }
      });
    }
  };
  const CustommDot = (props: any) => {
    const { onClick, active } = props;

    const CarouselItem1 = (
      <li
        className={`w-[15px] h-[15px] rounded-full ${
          active
            ? "bg-primary scale-125 transition-transform duration-300"
            : "bg-[#DDDDDD] scale-100 transition-transform duration-300"
        }`}
      >
        <button onClick={() => onClick()} />
      </li>
    );

    const carouselItems = Array(renderItems.length).fill(CarouselItem1);

    return (
      <button onClick={() => onClick()}>
        {React.Children.toArray(carouselItems)[index]}
      </button>
    );
  };

  return (
    <Carousel
      responsive={responsive}
      sliderClass="h-[660px]"
      infinite={true}
      showDots={true}
      slidesToSlide={1}
      swipeable={true}
      dotListClass="!relative gap-1"
      customDot={<CustommDot />}
      renderButtonGroupOutside={false}
      draggable={false}
      renderDotsOutside={true}
      containerClass="relative h-[660px] w-screen"
      arrows={false}
      itemClass="h-[660px]"
      customTransition="all 300ms ease-in-out"
      deviceType="lg"
      beforeChange={(nextSlide, { currentSlide, slidesToShow }) => {
        handleBeforeChange(nextSlide, currentSlide, slidesToShow);
      }}
    >
      {renderItems.map((item, idx) => (
        <div
          key={idx}
          className={`${
            index === idx
              ? "scale-100 transition-transform duration-300"
              : "scale-90 transition-transform duration-300"
          }`}
        >
          {item}
        </div>
      ))}
    </Carousel>
  );
}

export default CustomCarousel;