DEVLOG

Next.js ํ”„๋กœ์ ํŠธ :: carousel ๊ตฌํ˜„ํ•˜๊ธฐ ๋ณธ๋ฌธ

frontend/next.js

Next.js ํ”„๋กœ์ ํŠธ :: carousel ๊ตฌํ˜„ํ•˜๊ธฐ

meroriiDev 2023. 6. 22. 15:18
728x90
๋ฐ˜์‘ํ˜•
๐Ÿ“–  ๋ชฉ์ฐจ

     

    ๐ŸŽˆ Carousel์ด๋ž€?

    ํ”ํžˆ ์ด๋Ÿฌํ•œ ํ˜•์‹์˜ ๊ตฌ์กฐ๋ฅผ ์šฐ๋ฆฌ๋Š” ์Šฌ๋ผ์ด๋”๋ผ๊ณ  ๋ถ€๋ฅด๊ณคํ–ˆ๋‹ค.
    ๊ทธ๋Ÿฐ๋ฐ '์Šฌ๋ผ์ด๋” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ'๋ผ๊ณ  ๊ฒ€์ƒ‰์„ ํ•˜๊ณ  ์ฐพ์•„๋ณด๋ ค๊ณ  ํ•˜๋‹ˆ ํ•œ๊ตญ์—์„œ๋งŒ ์ด๋Ÿฐ ๊ตฌ์กฐ๋ฅผ ์Šฌ๋ผ์ด๋”๋ผ๊ณ  ํ•˜๊ณ  ์‚ฌ์‹ค์€ carousel์ด๋ผ๊ณ  ๋ถ€๋ฅด๋Š”๊ฒŒ ๋งž๋‹ค.


    carousel์€ ํšŒ์ „๋ชฉ๋งˆ๋ผ๋Š” ๋œป! ๋น™๋น™ ๋Œ์•„๊ฐ€๋Š”,, ๊ทธ๋Ÿฐ ๋Š๋‚Œ!

    ์˜์–ด๊ถŒ๋‚˜๋ผ์—์„œ ์ด๋Ÿฐ๊ฑธ ์Šฌ๋ผ์ด๋”๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ฒƒ ๊ฐ™๋‹ค!

    ์‚ฌ์‹ค ์ค‘์š”ํ•œ๊ฑด ์•„๋‹Œ๋ฐ ์ฐพ์•„๋ณด๋ฉด์„œ ํฅ๋ฏธ๋กœ์›Œ์„œ ๊ณต์œ ํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค :)

    ๐ŸŽˆ swiper

    ๋ฉ”์ธํŽ˜์ด์ง€์— ๋“ค์–ด๊ฐˆ ์บ๋Ÿฌ์…€์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋จผ์ € ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ถ€ํ„ฐ ์„ ํƒํ•ด์•ผํ–ˆ๋‹ค. ๋‹น์—ฐํžˆ ์ง์ ‘ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋„ˆ๋ฌด ๋น„ํšจ์œจ์ ์ผ ๊ฒƒ ๊ฐ™์•„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ์ฐพ์•„๋ณด๋Š”๋ฐ swiper์„ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๊ฐ™๊ณ  ๊ณต์‹๋ฌธ์„œ๋„ ์ •๋ฆฌ๊ฐ€ ์ž˜ ๋˜์–ด์žˆ๊ธธ๋ž˜ swiper์„ ์„ ํƒํ–ˆ๋‹ค.

    ๊ณต์‹ ์‚ฌ์ดํŠธ : https://swiperjs.com/react

    ํ‹ฐ๋น™ ์‚ฌ์ดํŠธ ๋””์ž์ธ์„ ์ฐธ๊ณ ํ–ˆ์„ ๋•Œ fadeํ˜•๊ณผ carouselํ˜• ์ด 2๊ฐ€์ง€์˜ ์Šฌ๋ผ์ด๋”๊ฐ€ ํ•„์š”ํ•œ๋ฐ swiper์œผ๋กœ ๋‘๊ฐ€์ง€ ๋ชจ๋‘ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ–ˆ๋‹ค.
    ๊ทธ๋ž˜์„œ ์ด๋ฒˆ์—๋Š” ํƒ€์ž…์— ๋”ฐ๋ผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์— ์ง‘์ค‘ํ–ˆ๋‹ค.

    ๊ธฐ๋ณธํ˜• carousel


    swiper์‚ฌ์šฉ๋ฒ•์€ setting์— ์žˆ๋Š” ๊ฒƒ๋“ค์„ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ๋งค์šฐ ๊ฐ„๋‹จํ–ˆ๋‹ค.

    export const Carousel = (props: CarouselProps) => {
      const { data } = props;
    
      return (
        <PosterLayout>
        <Swiper
            spaceBetween={10}
            slidesPerView={3}
            slidesPerGroup={3}
            loop={false}
            mousewheel={true}
            navigation={true}
            pagination={{
              clickable: true,
            }}
            effect={"slide"}
            autoplay={false}
            breakpoints={
                640: {
                  slidesPerView: 5,
                  slidesPerGroup: 5,
                },
                768: {
                  slidesPerView: 6,
                  slidesPerGroup: 6,
                },
                1024: {
                  slidesPerView: 7,
                  slidesPerGroup: 7,
                },
                1400: {
                  slidesPerView: 8,
                  slidesPerGroup: 8,
                },
            }
            modules={[Navigation, Pagination, EffectFade, Mousewheel, Autoplay]}
          >
              <SwiperSlide>...</SwiperSlide>
          </Swiper>
        </PosterLayout>
      );
    };
    

     

    fadeํ˜• carousel

    export const Carousel = (props: CarouselProps) => {
      const { data, fade } = props;
    
      return (
        <PosterLayout fade={fade}>
          <Swiper
            spaceBetween={10}
            slidesPerView={1}
            slidesPerGroup={1}
            loop={true}    //๋ฃจํ”„๋ฐ˜๋ณต
            navigation={true}
            pagination={{
              clickable: true,
            }}
            effect={"fade"}    //fadeํ˜• ์ดํŽ™ํŠธ
            autoplay={{    //์ž๋™์žฌ์ƒ
                delay: 5000,
                disableOnInteraction: false,
            }}
            modules={[Navigation, Pagination, EffectFade, Mousewheel, Autoplay]}
            onSlideChange={(c) => {    //์Šฌ๋ผ์ด๋“œ change์‹œ ํ˜„์žฌ index ๋ณ€๊ฒฝ
              setCurrentData(c.realIndex);
            }}
          >
        </PosterLayout>
      );
    };

     

    โ— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋‹ค!

    slide ๋‚ด๋ถ€ ๋ ˆ์ด์•„์›ƒ์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜๋ณต๋ฌธ์„ ๋Œ๋ ค ์ถœ๋ ฅํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ–ˆ๋Š”๋ฐ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋‹ˆ ์šฐ์ธก ํ•˜๋‹จ ์ž์„ธํžˆ๋ณด๊ธฐ ๋ฒ„ํŠผ์ด ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๋ฐ์ดํ„ฐ ๊ฐ’์œผ๋กœ๋งŒ ์ถœ๋ ฅ์ด ๋ผ์„œ ์–ด๋–ค ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ๋„ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ์นด๋“œ์˜ ์ƒ์„ธ๋กœ ์ด๋™ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค...

    fadeํ˜•์ด๋ผ ์Šฌ๋ผ์ด๋“œ๊ฐ€ ์œ„๋กœ ์ถ•์ ์ด ๋˜๋ฉด์„œ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๋ฒ„ํŠผ๋งŒ ๋…ธ์ถœ์ด ๋˜์–ด์„œ ๊ทธ๋žฌ๋˜ ๊ฒƒ

    ๊ทธ๋ž˜์„œ ์ค‘๋ณต๋„ ์ค„์ผ๊ฒธ ๋ฒ„ํŠผ์€ ํ•˜๋‚˜๋กœ ์œ ์ง€ํ•˜๊ณ  ํ˜„์žฌ ์Šฌ๋ผ์ด๋“œ์˜ id๋ฅผ ์•Œ์•„๋‚ด์–ด state๋กœ ๊ด€๋ฆฌํ•˜๋Š”์‹์œผ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ํ•ด๊ฒฐํ–ˆ๋‹ค.

      const [fadeData, setFadeData] = useState<number[]>([]);
      const [current, setCurrentData] = useState(0);
    
      useEffect(() => {
        if (fade && !fadeData.length) {
          const _idData = data.map((item: movieResult) => item.id);
          setFadeData(_idData);
        }
      }, [data, fade, fadeData]);

     

    ๐ŸŽˆ carousel ์ปดํฌ๋„ŒํŠธํ™”

    ์•ฝ๊ฐ„์˜ setting๊ณผ ์ถœ๋ ฅํ•ด๋‚ด๋Š” ํฌ์Šคํ„ฐ์˜ ๊ตฌ์กฐ์™€ ์Šคํƒ€์ผ๋งŒ ๋‹ค๋ฅด๊ธฐ๋•Œ๋ฌธ์— ์ด๋ฅผ ๊ณตํ†ต๋˜๋Š” ๋ถ€๋ถ„์„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋” ํŽธ๋ฆฌํ•˜์ง€ ์•Š์„๊นŒ?ํ•˜๋Š” ์ƒ๊ฐ์œผ๋กœ ์ปดํฌ๋„ŒํŠธํ™”๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค.

    export const Carousel = (props: CarouselProps) => {
      const { data, fade } = props;
      const [fadeData, setFadeData] = useState<number[]>([]);
      const [current, setCurrentData] = useState(0);
    
      useEffect(() => {
        if (fade && !fadeData.length) {
            //fade์˜ํ™” ๋ฐ์ดํ„ฐ์˜ id์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐฐ์—ด
          const _idData = data.map((item: movieResult) => item.id);
          setFadeData(_idData);
        }
      }, [data, fade, fadeData]);
    
      return (
        <PosterLayout fade={fade}>
          <Swiper
            spaceBetween={10}
            slidesPerView={fade ? 1 : 3}
            slidesPerGroup={fade ? 1 : 3}
            loop={fade || false}
            mousewheel={!fade}
            navigation={true}
            pagination={{
              clickable: true,
            }}
            effect={fade ? "fade" : "slide"}
            autoplay={
              fade
                ? {
                    delay: 5000,
                    disableOnInteraction: false,
                  }
                : false
            }
            breakpoints={
              fade
                ? {}
                : {
                    640: {
                      slidesPerView: 5,
                      slidesPerGroup: 5,
                    },
                    768: {
                      slidesPerView: 6,
                      slidesPerGroup: 6,
                    },
                    1024: {
                      slidesPerView: 7,
                      slidesPerGroup: 7,
                    },
                    1400: {
                      slidesPerView: 8,
                      slidesPerGroup: 8,
                    },
                  }
            }
            modules={[Navigation, Pagination, EffectFade, Mousewheel, Autoplay]}
            onSlideChange={(c) => {
              fade && setCurrentData(c.realIndex);
            }}
          >
            {data.map((result: movieResult) => {
              const { id, title, poster_path, backdrop_path } = result;
              return fade ? (
                <SwiperSlide key={id}>
                    // fadeํ˜• layout
                </SwiperSlide>
              ) : (
                <SwiperSlide key={id}>
                   // carouselํ˜• layout
                </SwiperSlide>
              );
            })}
          </Swiper>
          {fade && (
            <div className="btn-more">
              <Link href={`/contents/${fadeData[current]}`}>์ž์„ธํžˆ ๋ณด๊ธฐ </Link>
            </div>
          )}
        </PosterLayout>
      );
    };
    
    

    ์™„์„ฑ!!

     

    ๐Ÿ‘‰ Next?

    ๋‹ค์Œ์€ ๊ฒ€์ƒ‰์ด๋‚˜ ๋ฆฌ์ŠคํŠธ ์ „์ฒด๋ณด๊ธฐ ํด๋ฆญ์‹œ ๋ณด์—ฌ์ง€๋Š” ๋ฆฌ์ŠคํŠธ๋ชจ๋“œ์˜ ํŽ˜์ด์ง€์— infinite scroll์„ ๊ตฌํ˜„ํ•  ์˜ˆ์ •์ด๋‹ค.

    728x90
    ๋ฐ˜์‘ํ˜•
    Comments