티스토리 뷰

728x90
반응형

 

안녕하세요. Teus입니다.

 

지난번까지 해서 드디어 캘린더를 추가해서

 

모바일 청첩장이 컴퓨터 한 화면에 안들어올 정도가 되었습니다.

 

이번에는 모바일 청첩장에서 중요한 사진을 보여줄 수 있는 이미지갤러리를 추가하겠습니다.

# 1. 이미지갤러리

이미지갤러리는 기본적으로는 6장만 보여주고

 

사용자가 원한다면 펼치기를 통해서 추가적인 사진을 확인할 수 있게 해줍니다.

대표사진 삭제

사진 설명을 입력하세요.

이제 위 설계도에 맞게 코드를 작성합니다.

 

Gallery.jsx

import { useEffect, useState } from "react";
//src/assets/images에 있는 모든 이미지를 한번에 불러오기 위한 방법입니다.
const imagePaths = import.meta.glob('./assets/images/*.{png,jpg,jpeg,svg,webp}');

const Gallery  = ({title}) => {
    //접기/펼치기 상태를 유지하기 위한 stateV
    const [isflip, set_isfliep] = useState(true);\
    //화면에 표시해줄 이미지를 정하는 부분.
    const [images, set_images] = useState([]);
    //전체 이미지를 저장해줄 stateV. useRef를 사용해서 저장해도됨.
    const [all_images, set_all_images] = useState([]);
    useEffect(()=>{
      const loadImages = async () => {
        const imagePromises = Object.entries(imagePaths).map(([path, importImage]) =>
          importImage().then((module) => ({ path, src: module.default }))
        );
        const loadedImages = await Promise.all(imagePromises);

        //이미지를 1~18순서로 정렬시키는데, 문자열 기준 정렬이 되지 않게 만드는 코드
        loadedImages.sort((a, b)=>{
          let _a = a.path.split("/")
          let _b = b.path.split("/")
          _a = _a[_a.length-1].split(".")[0]
          _b = _b[_b.length-1].split(".")[0]
          return parseInt(_a) - parseInt(_b)
        })
        
        //첫 load시에는 6개의 image를 row = 2, col = 3으로 나눠서 보여줍니다.
        const temp = []
        for (let i = 0; i < 6; i++) {
          temp.push(loadedImages.slice(i*3, (i+1)*3))
        }
        set_images(temp.slice(0, 2));
        set_all_images(temp)
      }
      loadImages();
    } ,[])

    const flip_gallery = () => {
        //flip에 따라 row개수를 변경시켜서 images를 변경시켜줌
        const row_cnt = isflip ? 6 : 2;
        set_images([...all_images].slice(0, row_cnt))
        set_isfliep(!isflip)
      }
    return  (
    <>
      <h1>{title}</h1>
      {
      [images].map((v, i) => {
          return (
          v.map((v2, i2)=>{
          return (
              <div key = {i*100+i2*10} style = {{display:"flex"}}>
              {
                  [0, 1, 2].map((v3, i3) => {
                  return (
                    <img key = {v2[v3].path} src={v2[v3].src}/>
                  )
                  })
              }
              </div>
              )
          }) 
          )
      })
      }
      <div
        onClick={() => {flip_gallery()}}
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          marginTop : "5px",
          marginBottom : "20px",
        }}
      >
        {isflip?"더보기":"접기"}
      </div>
    </>
)}

export default Gallery 
 

그러면 아래처럼 이미지가 col = 3, row = 2의 형태로 나오고

 

접기-펼치기에 따라 변경되는것을 볼 수 있습니다.

 

 

 

 

하지만 지금은 이미지간 분리가 안되어있고, 화면에 정렬이 보기 좋지 않습니다.

img tag에 스타일링을 추가해줍니다.

 

Gallery.jsx

import { useEffect, useState } from "react";
//src/assets/images에 있는 모든 이미지를 한번에 불러오기 위한 방법입니다.
const imagePaths = import.meta.glob('./assets/images/*.{png,jpg,jpeg,svg,webp}');

const Gallery  = ({title}) => {
    //접기/펼치기 상태를 유지하기 위한 stateV
    const [isflip, set_isfliep] = useState(true);
    //화면에 표시해줄 이미지를 정하는 부분.
    const [images, set_images] = useState([]);
    //전체 이미지를 저장해줄 stateV. useRef를 사용해서 저장해도됨.
    const [all_images, set_all_images] = useState([]);
    useEffect(()=>{
      const loadImages = async () => {
        const imagePromises = Object.entries(imagePaths).map(([path, importImage]) =>
          importImage().then((module) => ({ path, src: module.default }))
        );
        const loadedImages = await Promise.all(imagePromises);

        //이미지를 1~18순서로 정렬시키는데, 문자열 기준 정렬이 되지 않게 만드는 코드
        loadedImages.sort((a, b)=>{
          let _a = a.path.split("/")
          let _b = b.path.split("/")
          _a = _a[_a.length-1].split(".")[0]
          _b = _b[_b.length-1].split(".")[0]
          return parseInt(_a) - parseInt(_b)
        })
        
        //첫 load시에는 6개의 image를 row = 2, col = 3으로 나눠서 보여줍니다.
        const temp = []
        for (let i = 0; i < 6; i++) {
          temp.push(loadedImages.slice(i*3, (i+1)*3))
        }
        set_images(temp.slice(0, 2));
        set_all_images(temp)
      }
      loadImages();
    } ,[])

    const flip_gallery = () => {
        //flip에 따라 row개수를 변경시켜서 images를 변경시켜줌
        const row_cnt = isflip ? 6 : 2;
        set_images([...all_images].slice(0, row_cnt))
        set_isfliep(!isflip)
      }
    return  (
    <>
      <h1>{title}</h1>
      {
      [images].map((v, i) => {
          return (
          v.map((v2, i2)=>{
          return (
              <div key = {i*100+i2*10} style = {{display:"flex"}}>
              {
                  [0, 1, 2].map((v3, i3) => {
                  return (
                    <div style = {{margin : "2%", border:"1px solid rgb(230, 224, 255)", borderRadius:"12px", width:"29%", height:"111.896px", overflow:"hidden"}}>
                        <img key = {v2[v3].path} src={v2[v3].src} height={"100%"} width={"100%"} alt="my image"/>
                    </div>
                  )
                  })
              }
              </div>
              )
          }) 
          )
      })
      }
      <div
        onClick={() => {flip_gallery()}}
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          marginTop : "5px",
          marginBottom : "20px",
        }}
      >
        {isflip?"더보기":"접기"}
      </div>
    </>
)}

export default Gallery
 

App.jsx

import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'


import { useEffect, useRef, useState } from 'react';
import Audiocomp from './Audiocomp'
import Topmsg from './Topmsg';
import Mainphoto from './Mainphoto';
import Invitation from './Invitation';
import Calendar from './Calendar';
import Gallery from './Gallery';

function App() {
  const debug = process.env.NODE_ENV === 'development'?"solid":"none";
  
  


  return (
    <>
      <div className='main-frame'>
        <div style={{ border: debug, textAlign: 'right' }}>
          <Audiocomp/>
        </div>
        <div className = "fade-in" style={{ border: debug}}>
          <Topmsg/>
        </div>
        <div className = "fade-in" style={{ border: debug}}>
          <Mainphoto/>
        </div>
        <div className = "fade-in" style={{ border: debug}}>
          <Invitation/>
        </div>
        <div className = "fade-in" style={{ border: debug}}>
          <Calendar/>
        </div>
        <div className = "fade-in" style={{ border: debug}}>
          <Gallery/>
        </div>
        <div className = "fade-in" style={{ border: debug}}>
          결혼식 장소
        </div>
        <div className = "fade-in" style={{ border: debug}}>
          신랑신부 계좌 정보
        </div>
        <div className = "fade-in" style={{ border: debug}}>
          카카오톡 공유하기 / 모청 주소 복사하기
        </div>
      </div>
    </>
  )
}

export default App
 

그러면 이제 18장의 사진만 준비하면

 

모바일 청첩장에 이쁜 사진을 하객들에게 보여줄 수가 있게됩니다.

 

 
 

 

 

728x90
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함