ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [3일차] 미니프로젝트 완료 및 피드백 반영
    내일배움캠프/미니프로젝트 2025. 2. 21. 12:20

    ✅ 오늘의 목표

    - 디자인 통일

    - 피드백 반영

    - 기능 개선

     

    ✅ 디자인 통일

     

    메인페이지 작업자 분께서 이렇게 예쁘게 메인을 디자인해주셨다.

     

    멤버 관리의 기존 디자인을

     

     

    아래와 같이 통일 시켜주었다.

     

     

    통일감을 주니 훨씬 보기좋아졌다.

     

    ✅ 피드백 반영

    header fix, 메인화면 소제목

     

    튜터님께 피드백 받은 내용이다.

     

    내가 한 번 해보기로 하였다.

     

    1. Header Fix 

    처음에는 Header 전체를 Fix 했었다.

     

     

    해당 작업을 한 후 팀원에게 이미지는 올라가고 Menu Nav 만 고정되면 어떨까라는  피드백을 받았다.

     

    그게 확실히 더 예쁠 것 같았다.

     

    구글링을 통해 방법을 찾아보았는데

     

    css 에서 

    position: sticky;

     

    를 사용하면 된다는 것을 알았다.

     

    sticky position의 동작 방식

    1. 브라우저가 처음 랜더링 되었을 때 sticky 요소는 문서 흐름에 따라 일반적인 위치에 배치됩니다.
    2. 스크롤이 지정된 위치에 도달할 때까지 sticky 요소는 일반적인 흐름대로 따라 이동합니다.
    3. 스크롤의 좌표가 지정된 위치에 도달하면 sticky 요소가 지정된 위치에 고정됩니다.
    4. 이제 지정된 위치 이하로 스크롤해도 해당 위치에 고정되어 유지됩니다.
    참조: https://coding-factory.tistory.com/951

     

     

    이렇게 menu 에 position: sticky; css를 적용했는데 아래와 같이 적용이 되질 않았다.

     

    그래서 문제가 무엇인지 한참을 살펴보고, sticky position은 부모 요소 안에서만 고정된다는 것을 알았다.

     

     $(function () {
        $("#header").load("common/header.html");
        $("#footer").load("common/footer.html");
    });

     

    우리는 해당 방식으로 header와 footer 를 load하고 있어서

     

    <body>
        <header>
            <div class="member-list">
                <img src="./assets/images/green_resized.png" alt="Member 1">
                <img src="/assets/images/red_resized.png" alt="Member 2">
                <img src="/assets/images/yellow_resized.png" alt="Member 3">
                <img src="/assets/images/white_resized.png" alt="Member 4">
                <img src="/assets/images/black_resized.png" alt="Member 5">
            </div>
            <nav class="menu">
                <a href="/pages/main.html">INTRO</a>
                <a href="/pages/main.html">HELMET</a>
                <a href="/pages/main.html">MEMBER CARD</a>
                <a href="/pages/guestBook.html">방명록</a>
            </nav>
        </header>
    </body>

     

    menu nav의 부모가 header였다. sticky 를 하려면 body를 부모로 지정해야했다.

     

    그래서 선택한 방법은 header가 load 된 후 header 에서 nav 를 빼서 header 밑에 배치시키는 방법을 선택했다. (야매)

    $("#header").load("common/header.html", function () {
        const menu = $("#header .menu").detach();
        $("#header").after(menu);
    });
    $("#footer").load("common/footer.html");

     

    이렇게 수정 후 확인을 해보니

     

    nav sticky 가 정상적으로 작동하는 것을 확인할 수 있었다!

    position: sticky;
    top: 0;       
    z-index: 1000;

     

    그리고 nav를 최상단에 고정하기 위해 top: 0;을 주었고 맨 앞에 배치하기 위해 z-index 를 1000주었다.

     

    2. 메인페이지 구역별 소제목

     

    메인 소개부분에 구역별로 소제목이 있어서 구분감을 줬으면 좋겠다는 피드백이었다.

     

     

    그래서 구역별로 소제목을 주고 margin 을 조금 더 줘서 해당 구역을 구분감을 더 주었다.

     

    ✅ 기능 개선

    1. 이미지 서버 저장

     

    기존에는 멤버를 등록할 때 이미지를 저장하는게 아니라, 이미지를 FileReader를 사용해서  Base64로 인코딩해서 그 결과값을 저장하는 형식으로 했었다.

    const reader = new FileReader()
    reader.onload = (e) => {
      img.src = e.target.result
    }
    reader.readAsDataURL(file)


    다른 분들의 코드를 보다가 이미지를  Firebase의 CloudStorage 사용하셔서 작성하신 것을 보았다.

     

    CloudStorage  를 사용하려면 Blaze 요금제를 사용해야한다고해서 고민했는데, 5GB/월 까지 무료로 사용가능하다해서 적용해보았다.

     

    이미지를 업로드 했을 때 사진을 서버로 전송하면 더미데이터가 쌓일 것을 고려하여 미리보기는 똑같이 base64로 인코딩해서 보여주었고 저장할 때 서버로 전송하는 방식을 택했다.

     

    const storageRef = ref(storage, `memberImages/${img.name}`)
    await uploadBytes(storageRef, img)
    const imgUrl = await getDownloadURL(storageRef)

     

    storageRef에 어느 경로에 파일을 저장할 것인지 선택해준 뒤 uploadBytes로 파일을 업로드해준다.

     

    그 뒤 getDownloadURL을 사용하여 업로드 된 파일의 url 을 return 받아서 서버에 저장해주었다.

     

     

    해당 함수들을 사용하여 서버로 이미지 전송을 하니 저장 시에 시간이 조금 걸렸다.

     

    그래서 사용자들이 지금 저장 중인건지 잘 모를 수 있을 것 같아서 저장 중인지 알 수 있도록 스피너를 구성하였다.

     

     

     

    저장이 시작되면 해당 스피너가 화면에 표시되고 완료시 alert 와 함께 스피너가 사라지도록 하여, 사용자가 저장 중인지 직관적으로 알 수 있게 되었다.

     

    2. Header 클릭 시 구역별로 이동

     

    페이지 내 특정 영역으로 스크롤 이동하도록 만들려면, header 에  각 영역에 고유한 id를 부여하고, header  메뉴 링크에서 해당 id를 참조하는 앵커 링크(#)로 연결하는 방식을 사용했다.

     

    각 구역별로 고유 id를 부여한다음

    function scrollToHashElement() {
        if (location.hash) {
            const target = document.querySelector(location.hash);
            if (target) {
                const headerOffset = 60;
                const elementPosition = target.getBoundingClientRect().top;
                const offsetPosition = elementPosition + window.scrollY - headerOffset;
    
                window.scrollTo({
                    top: offsetPosition,
                    behavior: "smooth"
                });
            }
        }
    }

     

    scroll-behavior을 이용한 함수를 작성하여 조금 더 세밀한 이동이 가능하도록 구현을 하였다.

     

     

     

     

     

    화면이 샤샤샥 움직이는 것을 볼 수 있다. 

     

    3. 구역별로 이동시 header active 효과 IntersectionObserver 함수.

     

     메뉴에 hover 시에는 색이 변하는데 화면을 이동하면 똑같이 active가 되면 좋겠다고 생각을 했다.

     

    <script>
        // 감시할 섹션들을 선택 (각 섹션에 고유한 id가 있어야 함)
        const sections = document.querySelectorAll('#intro, #helmet, #memberCard');
    
        // Intersection Observer 옵션 (50% 이상 보이면 active로 처리)
        const options = {
            root: null,
            rootMargin: '0px',
            threshold: 0.5
        };
    
        const observer = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    const id = entry.target.getAttribute('id');
                    // 모든 네비게이션 링크의 active 제거
                    document.querySelectorAll('.menu a').forEach(link => {
                        link.classList.remove('active');
                        // href에 해당 id가 포함되면 active 추가
                        if (link.getAttribute('href').includes('#' + id)) {
                            link.classList.add('active');
                        }
                    });
                }
            });
        }, options);
    
         // 각 섹션 관찰 시작
         sections.forEach(section => {
            observer.observe(section);
        });
    </script>

     

    InterserctionObserver 함수를 사용하여 해당 구역들을 감시하도록 구성하여 구역의 50%가 보이면 기존 active를 제거하고 해당 menu를 찾아서 active하도록 구성해주었다.

     

     

    페이지 이동시 nav가 active 되는 것을 볼 수 있다. 굿굿

     

    4. 페이지 깜빡임 현상 개선

     

    페이지가 header, footer 를 load 하고 또 그 후 css도 적용되고 그래서인지 화면이 구성될 때 깜빡임 현상이 있었다.

     

    그래서 해결한 방법이

    <style>
        body {
            visibility: hidden;
        }
    </style>

     

    body style에 visibillity: hidden; 으로 처음 페이지가 열릴 때 화면을 숨겨주었고,

     

      <script>
        $(function () {
            $("#header").load("common/header.html", function () {
                const menu = $("#header .menu").detach();
                $("#header").after(menu);
                $("#footer").load("common/footer.html", function () {
                    $("body").css("visibility", "visible");
                });
            });
        });
    </script>

     

    header load후 footer load를 하고 body visibillity를 visible로 변경하여 화면을 볼 수 있도록 하였다.

     

    그 후에는 깜빡임 현상이 사라졌다.

     

     

    ✅ 전체 페이지

    1. Main Page

     

    2. Member Detail

     

    3.Guest Book

     

    4. Admin Member List

     

    5.Admin Member Create

     

    이것으로 모든 페이지 작업이 완성 되었다. 팀원분들이 너무 다들 잘해주셔서 편하게 작업했던 것 같다.

     

    내일은 발표 자료 제작을 하고 개선사항이 없나 조금 더 볼 것 같다.

Designed by Tistory.