MUI

MUI - 모달로 슬라이더 만들기

AgileJung 2022. 7. 29. 05:00
728x90
반응형

MUI의 모달을 사용하여 모달 안에서 슬라이드를 구현해보자.

 

구현한 모습


import 부분

나는 Marsonry라는 레이아웃을 적용하였다. 똑같이 적용하고 싶다면 @mui/lab을 설치하면 된다.

import React, { useState } from 'react';
import styled from '@emotion/styled';
import { Masonry } from '@mui/lab';
import { Box, Modal, IconButton, Typography } from '@mui/material';
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';

 


 

함수 동작 부분

 const [open, setOpen] = useState(false);
  const [imgindex, setImgindex] = useState(0);

  const handleOpen = index => {
    setImgindex(index.target.id);
    setOpen(true);
  };

  const handleClose = () => setOpen(false);

  const backImg = () => {
    Number(imgindex) === 0
      ? setImgindex(movie_image.length - 1)
      : setImgindex(imgindex - 1);
  };

  const forwardImg = () => {
    setImgindex(Number(imgindex) + 1);
    if (imgindex === movie_image.length - 1) {
      setImgindex(0);
    }
  };

주의할점!

자바스크립트는 +와 - 를 문자와 숫자를 같은 타입이라고 생각하고 그대로 문자와 숫자를 더해버리기 때문에

숫자로만 판별해야 하는 조건에서는 Number()를 통해서 문자가 아닌 숫자라고 정해줘야 오류가 나지 않는다.

 

 

 


 

컴포넌트 UI 부분

<Box>
        <GalleryModal
          open={open}
          onClose={handleClose}
          aria-labelledby="modal-modal-title"
          aria-describedby="modal-modal-description"
          img={movie_image}
          imgindex={imgindex}
        >
          <ImgContainer>
            <GalleryButton sx={{ marginLeft: '-80px' }} onClick={backImg}>
              <ArrowBackIosIcon />
            </GalleryButton>

            <Img
              src={movie_image[imgindex]}
              img={movie_image}
              imgindex={imgindex}
            />

            <GalleryButton sx={{ marginLeft: '50px' }} onClick={forwardImg}>
              <ArrowForwardIosIcon />
            </GalleryButton>
            <Box sx={{ textAlign: 'center', marginTop: '10px' }}>
              <NowImg>{Number(imgindex) + 1}</NowImg>
              <TotalImg> /{movie_image.length}</TotalImg>
            </Box>
          </ImgContainer>
        </GalleryModal>
      </Box>

 


전체 코드

import React, { useState } from 'react';
import styled from '@emotion/styled';
import { Masonry } from '@mui/lab';
import { Box, Modal, IconButton, Typography } from '@mui/material';
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';

function MovieGallery({ movie_image }) {
  const [open, setOpen] = useState(false);
  const [imgindex, setImgindex] = useState(Number(0));

  const handleOpen = index => {
    setImgindex(index.target.id);
    setOpen(true);
  };

  const handleClose = () => setOpen(false);

  const backImg = () => {
    Number(imgindex) === 0
      ? setImgindex(Number(movie_image.length) - 1)
      : setImgindex(Number(imgindex) - 1);
  };

  const forwardImg = () => {
    setImgindex(Number(imgindex) + 1);
    if (imgindex === movie_image.length - 1) {
      setImgindex(0);
    }
  };

  return (
    <>
      <Box sx={{ width: '100%', minHeight: 429 }}>
        <Masonry columns={4} spacing={2}>
          {movie_image?.map((item, index) => (
            <div key={index}>
              <MasonryImg
                id={index}
                src={`${item}?w=162&auto=format`}
                srcSet={`${item}?w=162&auto=format&dpr=2 2x`}
                alt={item.title}
                loading="lazy"
                onClick={handleOpen}
                style={{
                  borderRadius: 8,
                  borderBottomLeftRadius: 8,
                  borderBottomRightRadius: 8,
                  display: 'block',
                  width: '100%',
                  boxShadow: '5px 7px 20px -4px rgba(0, 0, 0, 0.6)',
                }}
              />
            </div>
          ))}
        </Masonry>
      </Box>
      <Box>
        <GalleryModal
          open={open}
          onClose={handleClose}
          aria-labelledby="modal-modal-title"
          aria-describedby="modal-modal-description"
          img={movie_image}
          imgindex={imgindex}
        >
          <ImgContainer>
            <GalleryButton sx={{ marginLeft: '-80px' }} onClick={backImg}>
              <ArrowBackIosIcon />
            </GalleryButton>

            <Img
              src={movie_image[imgindex]}
              img={movie_image}
              imgindex={imgindex}
            />

            <GalleryButton sx={{ marginLeft: '50px' }} onClick={forwardImg}>
              <ArrowForwardIosIcon />
            </GalleryButton>
            <Box sx={{ textAlign: 'center', marginTop: '10px' }}>
              <NowImg>{Number(imgindex) + 1}</NowImg>
              <TotalImg> /{movie_image.length}</TotalImg>
            </Box>
          </ImgContainer>
        </GalleryModal>
      </Box>
    </>
  );
}
export default MovieGallery;

const ImgContainer = styled(Box)`
  position: relative;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 800px;
  box-shadow: 24px;
  padding: 40px;
  outline: none;
`;

const MasonryImg = styled.img`
  cursor: pointer;
  transition: all ease 0.5s;
  :hover {
    transform: scale(1.04, 1.04);
  }
`;

const Img = styled.img`
  border-radius: 16px;
  width: 100%;
`;

const GalleryButton = styled(IconButton)`
  position: absolute;
  top: 50%;
`;

const GalleryModal = styled(Modal)``;

const NowImg = styled(Typography)`
  display: inline;
  color: white;
  font-weight: bold;
`;
const TotalImg = styled(NowImg)``;
728x90
반응형