미니 팀프로젝트 | 팀소개 사이트 만들기 3

하영·2024년 7월 20일
0

팀프로젝트

목록 보기
4/27

각자 작업한 section들을 하나의 index.html로 합친 최종 파일이 완성되었다~!
전체적인 코드들도 복습하면서 중간중간 있었던 에러들도 담아보려한다.
코드복습 겸 회고? 라고 보면 좋을 이번 포스팅!

팀 소개 사이트 만들기 전체 코드

1. html

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>4조 코린이</title>
    <!-- cdn jquery -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js"></script>
    
    <!-- css -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.carousel.min.css"/>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.theme.default.css"/>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css"/>
    <!-- 작업한 css 파일 -->
    <link rel="stylesheet" href="./chat.css" />
    <link rel="stylesheet" href="./style.css" />
  </head>

  <body>
    <!-- header 서영진 -->
    <div class="team" id="team">
      <h1 class="title">팀 "코린이"를 소개합니다!</h1>
      <p class="team-content">
        안녕하세요! 팀 코린이입니다...! <br />웹 개발에 대한 열정과 호기심으로
        뭉친 프론트엔드 초보 개발자들입니다! <br />
        다양한 배경을 가진 팀원들이 모인 코린이는 각자의 강점을 살려 협력하며,
        사용자에게 더 나은 경험을 제공할 수 있는 멋진 웹 애플리케이션을
        개발하고자 노력하고 있습니다.
      </p>
      <div class="divBtn buttons">
        <button class="btn" id="introduceBtn">
          <span>팀 소개</span>
        </button>
        <button class="btn" id="memberBtn">
          <span>팀원</span>
        </button>
        <button class="btn" id="commentBtn">
          <span>댓글 달기</span>
        </button>
      </div>
    </div>

    <!-- introduce 이지영 -->
    <section class="card-section introduce" id="introduce">
      <div class="top_btn"></div>
      <h2 class="line-title">코린이 조는?</h2>
      <p class="card-subtitle">
        다양한 배경을 가진 팀원들이 모인 코린이는,
        <br />
        본인이 맡은 일에 끝까지 최선을 다하며, 할 수 있는 영역에서 최선을
        다합니다.
      </p>
      <div class="owl-carousel custom-carousel owl-theme custom_owl">
        <div
          class="item active"
          style="background-image: url(./image/card_img1.jpg)"
        >
          <div class="item-desc">
            <h3>우리팀만의 특징은?</h3>
            <p>꼼꼼하고 섬세하며 내향과 외향이 어우러져있어요~</p>
          </div>
        </div>
        <div class="item" style="background-image: url(./image/card_img2.jpg)">
          <div class="item-desc">
            <h3>우리팀의 궁극적인 목표</h3>
            <p>
              1. 자기가 맡은 임무는 끝까지 최선을 다하기! <br />
              2. 불화 없이 행복 코딩하기!
            </p>
          </div>
        </div>
        <div class="item" style="background-image: url(./image/card_img3.png)">
          <div class="item-desc">
            <h3>우리 팀의 약속!</h3>
            <p>
              1. 지각 절대 X <br />
              2. 일정 있을 때 사전 통보! <br />
              3. 눈치 주지 말기 <br />
              4. 소통 많이 하기! <br />
            </p>
          </div>
        </div>
        <div class="item" style="background-image: url(./image/card_img4.jpg)">
          <div class="item-desc">
            <h3>우리 팀의 강점</h3>
            <p>
              1. 꼼꼼하고 섬세해요 <br />
              2. 다양한 경험과 배경을 가지고 있어요 <br />
              3. 자기 주장이 뚜렷하고, 상대방의 의견을 존중하며, 의견을 자유롭게
              나눠요
            </p>
          </div>
        </div>
      </div>
    </section>

    <!-- member detail 송재헌 -->
    <section class="member_wrapper">
      <div class="wrap" id="team-member">
        <h2 class="team-title">코린이들을 소개합니다!</h2>
        <p>
          코린이들을 소개합니다! <br />
          마우스로 팀원의 이모지를 클릭해 보세요!
        </p>

        <div class="team-container"></div>
      </div>
    </section>

    <!-- comment 신희범 -->
    <section class="chat_wrapper">
      <div id="F_div">
        <div id="chat-title">
          <h2 class="chat-title">어떠셨나요?</h2>
          <p id="subtitle">
            지금까지 코린이들을 소개해 봤는데요!!
            <br />
            전체적으로 어떠셨는지 좋았던 점, 아쉬운 점을 남겨주세요!!
            <br />
            댓글로 이름과 내용을 작성해 주신 분들 중 추첨을 통해
            <br />
            <span id="present"> ♡서영진♡ 님이 " 치킨 기프티콘 "</span>을
            드립니다!!!!
            <br />
            모두 코멘트 남기고 치킨 먹어요 ^O^
          </p>
        </div>
        <div class="arrow">
          <img id="finger_animation" src="./image/finger.png" alt="animation" />
        </div>
        <div id="chatting-Bar">
          <p class="chatting-Bar-title">댓글창</p>
          <div id="chatting"></div>
          <div id="func">
            <input type="text" id="inputBox" placeholder="댓글을 남겨주세요" />
            <button id="postingBtn">
              <img src="./image/sendChat.png" id="sendChat" />
            </button>
          </div>
        </div>
      </div>
    </section>

    <!-- modal 김하영 -->
    <div id="modal_container">
      <div id="team_modal" class="team_modal">
        <span class="closeBtn" id="close-modal">
          <img src="image/close.png" alt="닫기버튼" />
        </span>
        <div id="member_image"></div>
        <h3 id="member_name"></h3>
        <p id="member_age"></p>
        <div id="member_content"></div>
      </div>
    </div>

    <!-- js -->
    <script src="script.js"></script>
    <script type="module" src="./comment.js"></script>
  </body>
</html>

작업한 파일을 합치면서 firebase를 사용한 파일(댓글창 section)만 별도로 관리하기로 했다. 소스가 복잡하기도 했고 마지막 날까지 가장 많이 수정작업이 들어갔기 때문에 최대한 충돌이나 에러를 막고자 했다.
script typemodule일 때는 따로 js파일을 만들고 가져오는 방법이 없는 줄 알았는데 그럴리 없지..ㅎ 이번 프로젝트를 통해서 type이 module일 때 html에 가져오는 방식에 대해 알게되었다.

💡 script type이 module일 때 html과 연결하는 법

<script type="module" src="js파일 경로"></script>

아주 간단해서 머쓱;;했던^^


2. css

댓글창 부분을 따로 관리하기로 했기 때문에 css도 2개로 만들었다.

::-webkit-scrollbar {
  display: none;
}

css 영역은 개인 디자인 취향이 들어가는거였고 특별히 새로 알게된 속성은 없어서 간단하게 위 코드만 정리하려고 한다.
댓글창을 만들었을 때 브라우저에서 기본설정 디자인이 안 예쁘기도 했고 굳이 스크롤바가 보일 필요가 없었다.
그래서 전체 스크롤바가 보이지 않도록 하는 속성을 사용했다.


3. javascript(전체)

자바스크립트를 정리하고 싶어서 이 포스팅을 쓴 것도 있어서ㅋㅋ 여기서부터는 조금 자세히 적어보려고 한다. 우선 댓글창을 제외한 전체 스크립트부터 복습해보자.

3-1. 변수 정리

  const teamContainer = document.querySelector(".team-container"); // 팀원 div박스를 담는 전체 큰 컨테이너(flex 속성 적용됨)
  const imagePath = "./image/";

  // 프로필 변수 (팀원소개 및 모달에서 사용)
  const members = [
    {
      name: "신희범",
      github: `${imagePath}github-remove.png`,
      velog: `${imagePath}velog-remove.png`,
      githubLink: "https://github.com/HBeom00",
      velogLink: "https://velog.io/@hbeom00/posts",
      backgroundImage: `${imagePath}shin_profile.png`,
      age: 23,
      advantages: "끈기 있다.",
      style: "꼼꼼하다.",
      tmi: "더위를 많이 타서 여름이 힘들다...",
      imgSrc: `${imagePath}shin.jpg`,
    },
    {
      name: "김하영",
      github: `${imagePath}github-remove.png`,
      velog: `${imagePath}velog-remove.png`,
      githubLink: "https://github.com/duddlfkd02",
      velogLink: "https://velog.io/@duddlfkd02/posts",
      backgroundImage: `${imagePath}kim_profile.png`,
      age: 26,
      advantages: "해야하는 일에 대해 계획성 있게 처리 가능해요",
      style: "겁이 많지만 악바리로 해내는 스타일",
      tmi: "빨래를 했는데 비가 옵니다...",
      imgSrc: `${imagePath}kim.jpeg`,
    },
    {
      name: "송재헌",
      github: `${imagePath}github-remove.png`,
      velog: `${imagePath}tstory-remove.png`,
      githubLink: "https://github.com/spmrsong",
      velogLink: "https://pokbeg.tistory.com/",
      backgroundImage: `${imagePath}song_profile.png`,
      age: 28,
      advantages: "궁금증이 정말 많아서 이것저것 도전해본다.",
      style:
        "비전공자라 굉장히 꼼꼼하게 찾아보지만 결국엔 GPT 의 도움을 받는다.",
      tmi: "24시간 에어컨 틀고 있어서 전기세가 걱정됩니다. 그리고 지금 음악 듣고 싶네요.",
      imgSrc: `${imagePath}song2.png`,
    },
    {
      name: "서영진",
      github: `${imagePath}github-remove.png`,
      velog: `${imagePath}velog-remove.png`,
      githubLink: "https://github.com/youngjin34",
      velogLink: "https://velog.io/@epik34/posts",
      backgroundImage: `${imagePath}seo_profile.png`,
      age: 30,
      advantages: "가끔씩 나서길 좋아한다..! 그래서 분위기를 좋게 만든다.",
      style: "chat gpt와 대화를 잘 나눈다....?ㅎㅎ",
      tmi: "맛있는 거 먹으면서 살 찔 때가 제일 좋아...",
      imgSrc: `${imagePath}seo.jpg`,
    },
    {
      name: "이지영",
      github: `${imagePath}github-remove.png`,
      velog: `${imagePath}velog-remove.png`,
      githubLink: "https://github.com/wldud7788",
      velogLink: "https://velog.io/@rooftop7788/posts",
      backgroundImage: `${imagePath}lee_profile.png`,
      age: 30,
      advantages: "마음먹은건 어떻게 해서든 꼭 해내요!",
      style: "계획적이고 체계적인걸 좋아하는 스타일",
      tmi: "강아지가 편식을 해요... 배가 불렀나봐요..",
      imgSrc: `${imagePath}lee.jpg`,
    },
  ];

  // header 버튼 변수
  const introduceBtn = document.getElementById("introduceBtn");
  const introduce = document.getElementById("introduce");
  const memberBtn = document.getElementById("memberBtn");
  const teamMember = document.getElementById("team-member");
  const commentBtn = document.getElementById("commentBtn");
  const comment = document.getElementById("F_div");

중간중간 작업하면서 생성한 변수는 각 파트별로 보면서 주석으로 정리할 예정!
전역변수로 사용했다고 볼 수 있는 변수는 이 정도로 적은 것 같다.

3-2. header 바로가기 버튼 기능 구현

const introduceBtn = document.getElementById("introduceBtn");
const introduce = document.getElementById("introduce");
const memberBtn = document.getElementById("memberBtn");
const teamMember = document.getElementById("team-member");
const commentBtn = document.getElementById("commentBtn");
const comment = document.getElementById("F_div");

introduceBtn.addEventListener("click", () => {
  window.scrollBy({
    top: introduce.getBoundingClientRect().top,
    behavior: "smooth",
  });
});
memberBtn.addEventListener("click", () => {
  window.scrollBy({
    top: teamMember.getBoundingClientRect().top,
    behavior: "smooth",
  });
});
commentBtn.addEventListener("click", () => {
  window.scrollBy({
    top: comment.getBoundingClientRect().top,
    behavior: "smooth",
  });
});

👩🏻‍💻 구현할 기능 : 매뉴버튼을 클릭하면 각 섹션별로 바로 이동할 수 있도록 만들기

  1. 각 섹션에 html에서 id 부여 후 변수로 지정하기
  2. .addEventListener("click"()=>) 클릭이벤트 사용
  3. scrollBy() 메소드로 세로로 이동하게 만든다.
  • scrollBy() 사용법
    window.scrollBy({
      top: 100, 
      left: 100,
      behavior: "smooth", // 부드럽게
    });
  1. getBoundingClientRect()paddingborder-width를 포함해 전체 엘리먼트가 들어 있는 가장 작은 사각형인 DOMRect 객체를 반환하므로 이를 활용해 top, 즉 최상단의 값으로 지정하여 그 위치로 이동하게 만든다.
  • getBoundingClientRect() 사용법
domRect = element.getBoundingClientRect();

적용한 코드

   commentBtn.addEventListener("click", () => {
  	window.scrollBy({
    top: comment.getBoundingClientRect().top, // 댓글창 전체 사각형에서의 top 값
    behavior: "smooth", // 부드럽게 이동
   });

3-3. 팀원 소개 페이지, 모달창 연결

members.forEach((member, idx) => {
    const memberDiv = document.createElement("div");
    memberDiv.className = "member";

    memberDiv.innerHTML = `
            <div class="photo member_content" id="member_content_${idx}">
                <img src="${member.backgroundImage}" alt="${member.name}">
                <div class="overlay">${member.name}</div>
            </div>
            <div class="icons">
                <a href="${member.githubLink}" target="_blank"><img src="${
      member.github
    }" alt="GitHub"></a>
                <a href="${member.velogLink}" target="_blank"><img src="${
      member.velog
    }" alt="${member.name === "송재헌" ? "Tstory" : "Velog"}"></a>
            </div>
        `;

    teamContainer.appendChild(memberDiv);

    // Add event listener for each member to show modal
    const memberContent = document.getElementById(`member_content_${idx}`);
    memberContent.addEventListener("click", () => {
      showModal(members[idx]);
    });
  });

👩🏻‍💻 구현할 기능 : members 객체 배열을 사용해서 html 하드코딩이 아닌 js로 각 값을 불러와서 화면에 출력, 각 인덱스 값을 활용해서 모달창과 연결

  1. createElement() 메소드로 멤버 콘텐츠를 담을 큰 div 박스를 만들고 memberDiv라는 변수라고 이름을 정했다.
  2. css 파일에서 미리 부여한 속성을 적용하기 위해 이 memberDivclassName으로 클래스명을 지정했다.
  3. forEach()를 사용해서 members 객체를 순회하면서 memberDiv 에 담기도록 하였다.
  4. 각 팀원의 정보가 담긴 memberDiv가 flex속성이 적용된teamContainer 안에 담기도록 appendChild 메소드를 주었다.
  5. memberContent 변수는 각 팀원 콘텐츠의 인덱스값을 감아서 이를 클릭할 때마다 해당 인덱스에 해당하는 콘텐츠가 모달로 불러와지도록 만들었다.

모달창은 내가 구현한 부분이라 따로 포스팅을 했고 슬라이더는 라이브러리를 사용한 부분이라 코드 이해만 하기로..!!


4. javascript (firebase를 사용하여 댓글창 만들기)

4-1. firebase 기본 세팅

import { initializeApp } from "https://www.gstatic.com/firebasejs/9.--.-/firebase-app.js";
import {
  getFirestore,
  collection,
  setDoc, // 문서 생성
  deleteDoc, // 문서 삭제
  doc,
  getDocs, // 원하는 데이터 읽기
} from "https://www.gstatic.com/firebasejs/9.--.-/firebase-firestore.js";
const firebaseConfig = {
  apiKey: "AIzaSyAw__Wgo******CCBgOS*******fLgM",
  authDomain: "miniproject4-5****a.firebaseapp.com",
  projectId: "miniproject4-5****a",
  storageBucket: "miniproject4-5****a.appspot.com",
  messagingSenderId: "2*******6",
  appId: "1:2****:web:3*******9d8b33",
  measurementId: "G-GY****9N",
};

개인정보를 위한(?).. 모자이크^^ 아무튼 초기 세팅은 이렇게 잡아주었다.

4-2. 작성한 내용 db저장

const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
async function postComment() {
  const addContent = $("#inputBox").val().trim();
  if (addContent !== "") {
    const date = new Date();
    const id = crypto.randomUUID();
    const dateTimeString = date.toLocaleString(); // Example: 2024. 7. 17. 오후 11:12:12
    const timeString = date.toLocaleTimeString(); // Example: 오후 10:10:03
    const commentData = {
      id: id,
      content: addContent,
      dateTimeStamp: dateTimeString,
      timeStamp: timeString,
    };
    try {
      await setDoc(doc(db, "chattings", id), commentData);
      alert("게시 완료!!");
      window.location.reload();
    } catch (error) {
      console.error("Error adding document: ", error);
      alert("게시 중 오류가 발생했습니다.");
    }
  } else {
    alert("내용을 입력해 주세요");
  }
}
$("#postingBtn").click(postComment);
$("#inputBox").keyup((e) => {
  if (e.key === "Enter") {
    e.preventDefault();
    postComment();
  }
});

postComment() 는 사용자가 댓글을 입력하면 그 데이터값을 저장하고 다시 불러와서 화면에 보여주는 기능을 모두 담은 큰 함수라고 할 수 있다. 이 함수를 부분적으로 뜯어보자.


🔍 코드 뜯어보기

const addContent = $("#inputBox").val().trim();
  if (addContent !== "") {
    const date = new Date();
    const id = crypto.randomUUID();
    const dateTimeString = date.toLocaleString(); // Example: 2024. 7. 17. 오후 11:12:12
    const timeString = date.toLocaleTimeString(); // Example: 오후 10:10:03
    const commentData = {
      id: id,
      content: addContent,
      dateTimeStamp: dateTimeString,
      timeStamp: timeString,
    };
  1. addContnet : inputBox의 값을 담은 변수
    addContnet가 공백이 아니라면 아래 데이터값을 객체로 저장해두었다.
    우리는 댓글을 남기면 내용, 남긴 시간을 보여주기로 했다.
    id 값을 만든 이유는 추후 삭제버튼을 구현할 때 삭제하려고 클릭한 그 내용의 id와 일치하는지 아닌지 비교해서 지우기 위해 각 댓글마다 고유한 id 값을 부여하였다.
    문자열로 된 랜덤값으로 받아오기 위해 crypto.randomUUID(); 를 사용하였다.
    ⭐️ crypto.randomUUID() : 범용적인 고유 식별에 사용될 id를 뜻하며 이 메소드를 사용하면 uuid를 라이브러리 없이도 생성할 수 있다. (문자열 랜덤!)
  2. commentData는 댓글창에 보여질 내용으로 에 고유 id값, content에는 추가한 내용, 그리고 시간들을 담았다.
try {
      await setDoc(doc(db, "chattings", id), commentData);
      alert("게시 완료!!");
      window.location.reload();
    } catch (error) {
      console.error("Error adding document: ", error);
      alert("게시 중 오류가 발생했습니다.");
    }
  } else {
    alert("내용을 입력해 주세요");
  }

우리가 원하는 데이터가 잘 불러와지면 firebase의 setDoc() 메소드를 활용해서 내용을 만들어주고 발생할 수 있는 경우를 try catch 구문으로 코드를 작성했다.

  1. 우리는 chattings라는 컬렉션에 id, 날짜, 내용을 담아두었다.
    그래서 모든 내용이 잘 담겼다면 경고창으로 게시완료가 되고 화면이 다시 로드된다.
  2. 만약에 데이터 등록 과정에서 오류가 발생했다면 오류 발생 경고창을 만들었다.
  3. 내용을 입력하지 않았을 경우에도 경고창을 띄우는 조건문을 넣어주었다.
$("#postingBtn").click(postComment);
$("#inputBox").keyup((e) => {
  if (e.key === "Enter") {
    e.preventDefault();
    postComment();
  }

게시 버튼을 누르면 모든 데이터가 담긴 (댓글 내용들) 함수가 실행되고, 엔터를 눌러도 똑같이 게시되도록 만들었다.


4-3. db내용 가져오는 함수 만들기

async function loadComments() {
  const dateContentTime = [];
  const dateTimeStamptArr = [];
  const querySnapshot = await getDocs(collection(db, "chattings"));
  querySnapshot.forEach((doc) => {
    const row = doc.data();
    const content = row.content;
    const dateTimeStamp = row.dateTimeStamp;
    const timeStamp = row.timeStamp;
    const id = row.id;
    dateContentTime.push([dateTimeStamp, content, timeStamp, id]);
    dateTimeStamptArr.push(dateTimeStamp);
  });
  dateTimeStamptArr.sort().reverse();
  const result = [];
  for (let i = 0; i < dateTimeStamptArr.length; i++) {
    for (let j = 0; j < dateContentTime.length; j++) {
      if (dateContentTime[j][0] === dateTimeStamptArr[i]) {
        result.push([
          dateContentTime[j][1],
          dateContentTime[j][2],
          dateContentTime[j][3],
        ]);
      }
    }
  }
  return result;
}

🔍 코드 뜯어보기

  1. 데이터를 가져오는 함수는 firebase의 getDoc()메소드를 활용했다.
  2. 이중배열을 사용했고 내용이 담긴 배열을 forEach로 순회시켜 값을 가져오도록 만들었다.
  3. 가져온 데이터는 push()로 담아주고 시간 배열을 정렬하기 위해 sort()메소드를 사용했다.
  4. 이중반복문을 돌려서 dateContentTime[j][0]dateTimeStamptArr의 인덱스가 각각 일치한다면,
    그에 맞는 내용과 시간이 result 값으로 담기도록 했다.

4-4. 삭제 기능 구현하기

async function deleteComment(docId) {
  const confirm = window.confirm("삭제하시겠습니까?");
  if (confirm) {
    try {
      await deleteDoc(doc(db, "chattings", docId));
      alert("댓글이 삭제되었습니다.");
      window.location.reload(); // 삭제 후 페이지 새로고침
    } catch (error) {
      console.error("Error removing document: ", error);
      alert("댓글 삭제 중 오류가 발생했습니다.");
    }
  }
}
(async () => {
  const comments = await loadComments();
  comments.forEach((comment, index) => {
    const commentIdx = comment[2];
    const isEvenIndex = index % 2 === 0; // 짝수인 내용만 우측 정렬이 되도록 하기 위해 작성
    const div = $("<div>")
      .attr("commentIdx", commentIdx)
      .text(comment[0])
      .css({
        border: "3px solid white",
        "border-radius": "10px",
        margin: "20px 0",
        padding: "8px 14px",
        "max-width": "60%",
        "font-size": "16px",
        background: "rgba(233, 233, 233, 0.5)",
        "text-align": isEvenIndex ? "left" : "right",
        "margin-left": isEvenIndex ? "0" : "auto",
        "word-break": "break-all",
      });

    const deleteBtnDiv = $("<div>").css({
      display: "flex",
      "justify-content": isEvenIndex ? "start" : "end",
      gap: "10px",
      "align-items": "center",
    });

    const timeDiv = $("<div>")
      .text(comment[1])
      .css({
        "font-size": "16px",
        "text-align": isEvenIndex ? "left" : "right",
      });

    const deleteBtn = $("<button>")
      .text("삭제")
      .attr("commentIdx", commentIdx)
      .click((e) => {
        const docId = $(e.target).attr("commentIdx");
        deleteComment(docId);
      })
      .css({
        outline: "none",
        border: "none",
        width: "40px",
        height: "25px",
        "border-radius": "5px",
        cursor: "pointer",
      });

    deleteBtnDiv.append(timeDiv);
    deleteBtnDiv.append(deleteBtn);

    $("#chatting").append(div);
    $("#chatting").append(deleteBtnDiv);
  });
})();

🔍 코드 뜯어보기

가장 오래 걸리고 문제도 많았지만 완성된 코드를 보면 딱히 설명할건 없다.
jquery에서 만든 태그는 css에서 따로 속성을 줘도 적용이 안 되는 것 같아서 (방법이 있겠지..? 찾아보자..) 바로 적용해주어서 코드가 길어졌다.

  1. 우리가 클릭한 삭제버튼의 id와 input박스에 입력한 id(위에서 우리가 객체로 담은 그 id)와 일치하는지 속성을 비교하기 위해 attr 메소드를 사용했다.
  • attr 사용법 (javascript에서는 setAttribute 같은 것!)
.attr( attributeName, value )
//선택한 요소에 속성을 추가함
$( 'h1' ).attr( 'title', 'Hello' );
//h1 요소에 title 속성을 추가하고 그 값은 'Hello'로 한다.

위 구문대로 작성하면 우리는 버튼이라는 요소에 "commentIdx" 속성을 추가하고 comment[2]값 (우리는 id가 [2] 인덱스였다) commentIdx 로 적어준 것이다.
2. 삭제버튼이 input박스 바로 다음에 붙도록 하기 위해 append 메소드를 사용했다.




새로 알게된 메소드, 속성 그리고 공부할 내용

  • attr( attributeName, value ) 으로 준 속성값을 비교해서 원하는 기능을 구현 방식 (이번 프로젝트에서는 id값 비교)
  • crypto.randomUUID() uuid 문자열 랜덤으로 생성하는 속성
  • firebase의 메소드들 (getDoc, setDoc, deleteDoc 등)
  • CRUD

^ 우리끼리 하다가 결국 안 돼서 단체로 쌤 방으로 들어가버림ㅋㅋㅋㅋ

첫 프로젝트를 마무리하며

정말 정말 어색한 첫날이었고 이 분위기로 12시간씩 5일동안 프로젝트 하나를 완성할 수 있을까 걱정이 컸다. 와이어프레임 하나 잡는것도 생각보다 오래걸렸다. 시간이 지나면서 점점 친해지고 서로 잘 만들고 싶은 욕심이 생기다보니 온라인임에도 불구하고 서로 어려워하는 부분도 도와주고 화면공유를 엄청나게 해서 하나씩 구현해나갔다.

😍 좋았던 점

  1. 같은 기능이더라도 사람마다 코딩방식이 다르고 생각하는 방식이 달라서 훨씬 깔끔한 코드를 만들 수 있었다.
  2. 다들 초보자이지만 그동안 공부하고 써봤던 메소드들을 공유하고 설명해주면서 새로 배운 메소드와 구문이 많아서 공부할 수 있었다.
  3. 기능 구현을 못하면 포기하지 않고 다같이 도와주고 해결할 수 있어서 결과물을 만들 수 있다는게 너무 좋았다.

😥 아쉬웠던 점

  1. 댓글창 만드는 부분에서 CRUD를 고려하지 않고 사전캠프때 들었던 강의를 활용해서 만들어내는 것에 초점을 맞추다보니, 삭제버튼이나 생성버튼을 만드는데 코드가 조금 꼬여서 어려웠다. 결국 생성(update)는 시간관계상 구현하지 못했는데 다음에 작업을 한다면 CRUD와 시간 배분에 신경써야겠다는 생각이 들었다.

  2. 각자 코딩 공부 기간이 다르고 그에 따라 실력도 달랐고 팀프로젝트 경험이 없다보니 작업 방식이 달라 코드를 합칠 때 조금 어려움이 있었다. 작업 들어가기 전 code convention을 정하긴했지만 더욱 세세하게 적었다면 좋았을 것 같다.

  3. 각 섹션별로 구현하다보니 사실 댓글창 기능 부분의 코드는 이해가 되다가 말아서 아쉬웠다. 삭제 기능을 구현할 때는 다같이 해보기로 했고 계속 마이크를 켜서 소통하고 화면공유하면서 서로의 코드를 보고 에러를 고쳐나갔다. 개인시간을 내서라도 코드를 다시 읽고 이해하고 나 혼자 다시 구현해봐야겠다.

  4. 각자 작업한 파일을 하나로 합쳤는데 지금은 미니프로젝트여서 큰 문제가 없지만 실무에서는 나누어서 파일을 관리해야 유지보수나 관리가 편리하다고 한다. 각 섹션이나 기능별로 html, css, js 파일을 나눠 작업하도록 하자.

🧐 개선할 점

  1. 퍼블리셔 작업하던 습관을 버리고 '기능구현'에 집중해서 작업하기
  2. CRUD를 늘 고려하며 작업하기
  3. 처음 기획하는 부분과 code convention을 확실하게 정하고 자주 소통하고 공유하기
  4. git을 활용할 때 각자 branch를 사용하고, commit 충돌이 나지 않도록 버전관리에 신경쓰기
  5. 중복된 코드, 필요없는 코드 꼭 더블체크하기
  6. 기능별로 파일 나누어서 작업하고 asset 파일 만들어서 합치기


다음주부터는 자바스크립트 강의와 수준별학습을 한다고 하는데 다음 팀프로젝트에서 민폐가 되지 않도록 진짜 진짜 꼼꼼하고 철저하게 공부해야겠다🔥
재미있었고 힘들었고 아쉽지만 뿌듯한 첫 미니프로젝트 끝!⭐️

profile
왕쪼랩 탈출 목표자의 코딩 공부기록

0개의 댓글

관련 채용 정보