Notice
Recent Posts
Recent Comments
Link
«   2025/03   »
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 29
30 31
Archives
Today
Total
관리 메뉴

heyday2024 님의 블로그

[사전캠프 퀘스트] TO DO LIST 만들기 본문

프론트엔드 부트캠프

[사전캠프 퀘스트] TO DO LIST 만들기

heyday2024 2024. 9. 19. 11:53

DOM( Document Object Model ) 이란?

 HTML, XML 문서의 프로그래밍 interface로, 쉽게 말해 HTML문서를 브라우저가 이해할 수 있도록 만든 Tree 자료구조!

  • DOM은 nodes와 objects로 문서를 표현함.

TO-DO-LIST

할 일을 추가할 수 있는 투두리스트 웹페이지.

https://todolistforonlytoday.netlify.app/

 

투두리스트

 

todolistforonlytoday.netlify.app

기능

  • 할일을 입력창에 입력하고,추가버튼(+)을 누르면 할일이 추가됨.
  • 추가된 항목은 delete버튼, 할일 내용, 체크박스를 포함하고 있음.
  • delete 버튼을 누르면 항목 사라짐.
    const inputArea = document.getElementById("text-list");
    const addBtn = document.querySelector(".add-btn");
    const listBoard = document.querySelector(".list");
    
    addBtn.addEventListener("click", function () {
      const inputText = inputArea.value.trim();
    
      if ((inputText === "")) {
        // 사용자가 어떤 내용도 적지 않고, 추가하기 버튼 눌렀을 때
        alert("해야 할 일을 입력해주세요.");
        // 그리고 아무 추가적인 동작도 하지 않도록 리턴해주기
        return;
      }
    
      //새로운 listed-item 요소 만들고, 클래스 이름 listed-item으로 설정
      const newItem = document.createElement("div");
      newItem.classList.add("listed-item");
    
      // 고유한 id를 생성하는 법: 시간(날짜)은 계속 흐르니까 계속 바뀜. 즉, 시간(+날짜)을 이용해 고유한 아이디 만들기 좋음.
      const newId = Date.now(); //시간 기반 unique ID 생성
    
      const checkbox = document.createElement("input");
      checkbox.type = "checkbox";
      checkbox.id = newId;
      // name은 아마 데이터를 백엔드로 보낼때 사용. 지금은 사용하지 않지만, 그래도 만들었음.
      checkbox.name = `to-do-${newId}`;
    
      const label = document.createElement("label");
      // label의 for을 id로 연결함으로서, label 즉 보여지는 text를 클릭해도 checked 처리 되게하기.
      label.htmlFor = newId;
      label.classList.add("tasks");
    
      //입력한 내용 버튼 누르면 내용 그대로 추가되게함
      label.textContent = inputText;
    
      // 삭제버튼 생성
      const deleteButton = document.createElement("button");
      deleteButton.type = "button";
      deleteButton.classList.add(
        "btn",
        "btn-outline-secondary",
        "delete-btn",
        "material-symbols-outlined"
      );
    
      deleteButton.textContent = "delete";
    
        // 삭제 버튼 클릭 시 항목 삭제
      deleteButton.addEventListener("click", function () {
        listBoard.removeChild(newItem); // 해당 항목 삭제
      });
    
      // 새로운 항목을 listBoard에 추가
      newItem.appendChild(checkbox);
      newItem.appendChild(label);
      newItem.appendChild(deleteButton);
      listBoard.appendChild(newItem);
    
      // 입력 필드 초기화
      inputArea.value = "";
    });

    • trim(): 문자열의 양쪽 끝에서 공백 문자(스페이스, 탭, 줄바꿈 등)를 제거하는 메서드. 문자열 내부의 공백은 제거하지 않음.
    • createElement(): HTML 문서에 새로운 요소를 동적으로 생성하는 메서드. 메서드를 호출할 때 태그 이름을 인자로 전달하여 해당 태그의 새로운 DOM 요소를 만들어냄.
    • classList.add(): 선택한 요소의 class 목록에 새로운 클래스를 추가하는 메서드. 여러 개의 클래스를 동시에 추가 가능.
    • Date.now(): 현재 시간을 밀리초 단위로 반환하는 정적 메서드. 고유한 ID를 생성하거나, 시간 기반의 값을 계산할 때 사용.
    • removeChild(): DOM에서 선택한 요소의 자식 노드를 제거하는 메서드.
    • appendChild(): 선택한 요소에 자식 노드를 마지막에 추가하는 메서드. 추가되는 노드는 반드시 DOM 요소여야함.

 

 

  •  체크 박스 디자인을 좀 더 보기 좋게 바꿨고, label 또는 체크박스 클릭 시 task가 완료됨을 보여줌(line-through)
    • 체크박스
      • id: HTML 요소를 유일하게 식별하는 데 사용(체크박스를 식별하는 유일한 식별자)
      • name: 주로 폼(form) 안에서 데이터를 서버로 보낼 때 사용. 같은 name을 가진 여러 요소가 있을 수 있으며, 서버에 전송될 때 해당 요소들의 값이 name 속성을 기준으로 전달됨.
      • for: label 태그의 for 속성은 그 레이블(label)이 어떤 폼 요소와 연결되는지를 지정. for 속성에 들어가는 값은 연결하려는 폼 요소의 id 값과 동일해야함
        • 이렇게 연결하면, 사용자가 해당 레이블을 클릭할 때 자동으로 그 폼 요소가 선택됨!!
    <input type="checkbox" id="1" name="to-do1" checked />
    <label class="tasks" for="1">해야할 일1</label>

 

  • 체크박스 디자인 바꾸기 
  input[type="checkbox"] {
    display: none;
  }
  input[type="checkbox"] + label {
    display: inline-block;
    position: relative;
    padding-left: 30px;
    cursor: pointer;
  }
  input[type="checkbox"] + label::before {
    display: block;
    content: "";
    font-size: 20px;
    width: 20px;
    height: 20px;
    line-height: 20px;
    text-align: center;
    position: absolute;
    left: 0;
    top: 6px;
    border: 1px solid #ddd;
    color: lightcoral;
  }

  input[type="checkbox"]:checked + label::before {
    content: "✔";
  }

`display: none;`으로 기존 체크박스 안보이게하기.
`+`: 인접 형제 결합자(adjacent sibling combinator)로, 특정 요소 바로 뒤에 오는 형제요소 선택 시 사용
`::before`: 가상요소로, **무조건 `content`요소 속성을 사용해야함**. 이 속성으로 삽입할 텍스트를 지정하고 이를 선택한 요소의 내용 앞에 추가함. 실제 HTML문서에 존재하지 않지만, 시각적으로 요소 앞에 추가된 내용처럼 보임.
+ `inline-block`:  inline-block으로 지정된 엘리먼트는 기본적으로 inline 엘리먼트처럼 한 줄에 다른 엘리먼트들과 배치된다. 하지만 inline 엘리먼트에서 불가능하던 width와 height 속성 지정 및 margin과 padding 속성의 상하 간격 지정이 가능

 

  • 글 중앙에 선 긋기
  input[type="checkbox"]:checked + label {
    text-decoration: line-through;
    /* 글 중앙에 선 긋는 효과 넣어서 task 완료 표시해주기 */
  }
  • checkbox가 checked되면, 그 인접형제요소인 label에 중앙선 효과 적용됨.

Html

<!DOCTYPE html>
<html lang="kr">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>투두리스트</title>
    <!-- 부트스트랩 -->
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
      crossorigin="anonymous"
    />
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
      crossorigin="anonymous"
    ></script>
    <!-- 구글 아이콘 써보기 -->
    <link
      rel="stylesheet"
      href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0"
    />
    <link rel="stylesheet" href="./main.css" />
    <script defer src="./main.js"></script>
  </head>
  <body>
    <div class="top">
      <h1>TO DO LIST</h1>
    </div>
    <div class="container">
      <div class="button_area">
        <div class="add">
          <input
            type="text"
            id="text-list"
            placeholder="해야 할 일을 적어주세요."
          />
          <button
            type="button"
            class="btn btn-outline-secondary add-btn material-symbols-outlined"
          >
            add
          </button>
        </div>
      </div>
      <div class="list">
        <!-- <div class="listed-item">
          <input type="checkbox" id="1" name="to-do1" checked />
          <label class="tasks" for="1">해야할 일1</label>
          <button
            type="button"
            class="btn btn-outline-secondary delete-btn material-symbols-outlined"
          >
            delete
          </button>
        </div> -->
      </div>
    </div>
  </body>
</html>

 

CSS

@import url("https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100..900&display=swap");

* {
  font-family: "Noto Sans KR", sans-serif;
  font-optical-sizing: auto;
  font-weight: 400;
  font-style: normal;
}

body {
  background-image: url("https://img.freepik.com/premium-vector/graph-paper-texture-blank-note-paper_391639-2862.jpg");
  display: flex;
  justify-content: center;
  /* 부모요소의 주 축(가로축)에서 자식 요소들을 가운데로 정렬 */
  align-items: center;
  /* 교차 축에서의 정렬(세로축 정렬) */
  flex-direction: column;
  padding: 50px 0;
  margin: 0 40px;
}

h1 {
  font-weight: 700;
  font-size: 80px;
}
.container {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 30px 0;
  flex-direction: column;
}
.button_area {
  display: flex;
  width: 100%;
  padding-bottom: 40px;
  /* background-color: #f8f2df; */
  justify-content: center;
}

#text-list {
  border-radius: 5px;
  border: solid 1px lightslategray;
  margin-right: 5px;
  padding-left: 10px;
  width: 60vb;
  height: 100%;
  font-size: 30px;
  background-color: rgb(248, 248, 234);
}

.add-btn {
  height: 100%;
  font-size: 30px;
  background-color: rgb(252, 239, 196);
  margin-top: -16px;
}

.listed-item {
  background-color: rgb(252, 245, 210);
  border-radius: 10px;
  padding: 10px 10px;
  width: fit-content;
  font-size: 20px;
  margin-bottom: 20px;
}

input[type="checkbox"] {
  display: none;
}
input[type="checkbox"] + label {
  display: inline-block;
  position: relative;
  padding-left: 30px;
  cursor: pointer;
}
input[type="checkbox"] + label::before {
  display: block;
  content: "";
  font-size: 20px;
  width: 20px;
  height: 20px;
  line-height: 20px;
  text-align: center;
  position: absolute;
  left: 0;
  top: 6px;
  border: 1px solid #ddd;
  color: lightcoral;
}

input[type="checkbox"]:checked + label::before {
  content: "✔";
}
input[type="checkbox"]:checked + label {
  text-decoration: line-through;
  /* 글 중앙에 선 긋는 효과 넣어서 task 완료 표시해주기 */
}

.delete-btn {
  padding: 5px;
  margin-left: 15px;
}

 

JS

const inputArea = document.getElementById("text-list");
const addBtn = document.querySelector(".add-btn");
const listBoard = document.querySelector(".list");

addBtn.addEventListener("click", function () {
  const inputText = inputArea.value.trim();

  if ((inputText === "")) {
    // 사용자가 어떤 내용도 적지 않고, 추가하기 버튼 눌렀을 때
    alert("해야 할 일을 입력해주세요.");
    // 그리고 아무 추가적인 동작도 하지 않도록 리턴해주기
    return;
  }

  //새로운 listed-item 요소 만들고, 클래스 이름 listed-item으로 설정
  const newItem = document.createElement("div");
  newItem.classList.add("listed-item");

  // 고유한 id를 생성하는 법: 시간(날짜)은 계속 흐르니까 계속 바뀜. 즉, 시간(+날짜)을 이용해 고유한 아이디 만들기 좋음.
  const newId = Date.now(); //시간 기반 unique ID 생성

  const checkbox = document.createElement("input");
  checkbox.type = "checkbox";
  checkbox.id = newId;
  // name은 아마 데이터를 백엔드로 보낼때 사용. 지금은 사용하지 않지만, 그래도 만들었음.
  checkbox.name = `to-do-${newId}`;

  const label = document.createElement("label");
  // label의 for을 id로 연결함으로서, label 즉 보여지는 text를 클릭해도 checked 처리 되게하기.
  label.htmlFor = newId;
  label.classList.add("tasks");

  //입력한 내용 버튼 누르면 내용 그대로 추가되게함
  label.textContent = inputText;

  // 삭제버튼 생성
  const deleteButton = document.createElement("button");
  deleteButton.type = "button";
  deleteButton.classList.add(
    "btn",
    "btn-outline-secondary",
    "delete-btn",
    "material-symbols-outlined"
  );

  deleteButton.textContent = "delete";

    // 삭제 버튼 클릭 시 항목 삭제
  deleteButton.addEventListener("click", function () {
    listBoard.removeChild(newItem); // 해당 항목 삭제
  });

  // 새로운 항목을 listBoard에 추가
  newItem.appendChild(checkbox);
  newItem.appendChild(label);
  newItem.appendChild(deleteButton);
  listBoard.appendChild(newItem);

  // 입력 필드 초기화
  inputArea.value = "";
});

 

 

달리기반 끝!