230424 - 투두리스트

백승연·2023년 4월 26일
1

🚩 javascript

투두리스트(일정관리) 2일차 코드 작성

📝 내용

  • 지금까지 배웠던 것을 응용하여 투두리스트 작성


✒️ 사용법

입력

css

@charset "UTF-8";

:root { --bgWhite: #ffffff; --bgTrasW: rgba(255,255,255,0.7); --bgTrasW2: rgba(255,255,255,0.85); --bgPink: #ffd6e1; }
body { font-family: Verdana, Geneva, Tahoma, sans-serif; background: #3257f1; background: linear-gradient(151deg,#3257f1 20%, #bcfff5 60%, #ffffff 75%, #eca7df 95%, #f897d6 100%); }
.container { border: 5px solid red; display: flex; flex-direction: column; row-gap: 2em; height: 100vh; max-width: 1000px; overflow-y: auto; padding: 3rem 1rem; margin: auto; }
.container form { display: flex; column-gap: 2rem; }
.container input { width: 100%; height: 40px; outline: none; border: none; padding: 0 10px; border-radius: 4px; background: var(--bgTrasW2); }
.container input:focus { background: var(--bgWhite); }
.container button { width: 200px; height: 40px; border-radius: 4px; outline: none; border: none; cursor: pointer; background: var(--bgTrasW); transition: .3s; }
.container button:hover { background: var(--bgWhite); }
.blocks { border: 2px solid blue; flex: 1; display: grid; grid-template-columns: repeat(3, 1fr); column-gap: 3rem; }
.block { display: flex; flex-direction: column; row-gap: 1.5rem; background: var(--bgTrasW2); padding: 1.5rem; border-radius: 4px; box-shadow: 1px 1px 5px rgba(0,0,0,0.7); }
.list { border: 3px solid orange; flex: 1; display: flex; flex-direction: column; row-gap: 0.8rem; }
.item { background: var(--bgWhite); padding: 1rem; border-radius: 4px; box-shadow: 0 0 3px rgba(0,0,0,0.3); }
.item:hover { background: var(--bgPink); cursor: pointer; }
@media(max-width:750px) {
  .blocks { display: flex; flex-direction: column; row-gap: 1rem; column-gap: 3rem; }
  .block { flex: 1; }
}

html

<div class="container">
  <form>
    <input type="text" placeholder="할 일을 입력하세요" required>
    <button type="submit">Add</button>
  </form>
  <div class="blocks">
    <div class="block">
      <h2>🚩 To do</h2>
      <div id="todo" class="list">
        <div id="" class="item">
          입력내용1
        </div>
      </div>
    </div>
    <div class="block">
      <h2>🚴‍♀️ Doing</h2>
      <div id="doing" class="list">

      </div>
    </div>
    <div class="block">
      <h2>✅ Done</h2>
      <div id="done" class="list">

      </div>
    </div>
  </div>
</div>

js

const form = document.querySelector("form");
const boxes = document.querySelectorAll(".list");

// 출발, 이동(도착)시점의 .list의 id이름
let from, to;

// * 2-3. 배열 생성 (localStorage에 저장하기 위함)
let todoList = [];
let doingList = [];
let doneList = [];
let lists = { // 3개의 list들을 객체 형태로 묶음
  // id이름을 배열의 이름과 맞춤 (key값과 id값이 같게)
  todo: todoList, // ? id값을 받아옴?
  doing: doingList,
  done: doneList
};

// * 2-2. 각 list들 위에 올라갔을 때 발생하는 함수 정의
// .list가 드래그 되는 것을 인식
const dragOver = (event) => {
  event.preventDefault(); // 마우스 커서 금지 표시 대신 +표시 생기게 함
  // console.log("반응하는 list의 id는?", event.target.id);

  // const targetId = event.target.id; // 아래와 같은 코드
  const { id:targetId } = event.target; // 마우스가 지나가는 곳의 id를 가져옴
  const listIds = Object.keys(lists); // 오브젝트의 키값만 가져옴

  if (listIds.includes(targetId)) { // 마우스가 지나가는 곳 id가 셋 중 하나와 같을 떄만
    to = targetId; // 도착(이동) 지점을 의미하는 to에 아이디를 넣는다.
  }

  console.log(to);
}

// * 2. 드래그 시작 시 발생하는 함수 정의
const dragStart = (event) => {
  // console.log(event.target.parentElement.id);
  from = event.target.parentElement.id; // 드래그 시작하는 지점. list의 id
  console.log(from); 
}
// * 2-4. 드래그 종료 시 발생하는 함수 정의. 다른 list로 옮긴 아이템을 삭제
const dragEnd = (event) => {
  // console.log("드래그 끝");
  if (from === to) { return; } // 같은 list 내부에서 움직일 때는 안 지워지게 함
  event.target.remove(); // 출발점 list에서는 지워줌

  const { id } = event.target; // 마우스가 지나가는 곳의 id를 가져옴

  // * 2-6. 내가 지운 item의 아이디와 다른 item의 아이디가 같은 것이 있으면 안됨
  lists[from] = lists[from].filter((item) => {
    if (item.id !== id){
      return item;
    } else {
      createElement(to, item);
    }
  })
  // console.log(from, lists[from]);
  // console.log(to, lists[to]);

  // * 3. 로컬스토리지에 저장하는 함수 실행 (로컬스토리지 업데이트)
  saveList(from);
  saveList(to);
}

// * 5. 우클릭으로 삭제하는 함수 정의
const removeItem = (event) => {
  event.preventDefault();
  const { id } = event.target;
  const { id:parentId } = event.target.parentElement;
  // console.log(parentId);

  event.target.remove(); // 이 코드만 작성하면 로컬스토리지에서는 삭제 안됨
  // * 5-2. 로컬스토리지에서도 삭제하도록 하는 코드
  lists[parentId] = lists[parentId].filter((aa) => {
    return aa.id !== id;
  })
  saveList(parentId);
  // console.log(parentId, lists[parentId]);
}

// * 1-2. item을 넣을 html 태그를 만드는 함수 정의
const createElement = (listId, newTodo) => { // listId = .list (html class), 아래 실행구에서 넘어온 newTodo
  const list = document.querySelector(`#${listId}`); // todo, doing, done 중 뭐가 들어올지 모르기 때문
  const item = document.createElement("div"); // div 생성

  item.id = newTodo.id; // 받아온 id를 새로 만든 item의 id에 넣음
  item.innerText = newTodo.text; // item 안에 글씨 넣음
  item.classList.add("item"); // item 클래스 추가
  
  // * 2. 드래그 기능 추가 (item을 만들 때 처음부터 가지고 있게 추가)
  item.draggable = true; // 드래그 할 수 있는 기능 추가
  item.addEventListener("dragstart", dragStart); // 드래그 시작 시 발생하는 함수(이벤트 인지)
  item.addEventListener("dragend", dragEnd); // 드래그 종료 시 발생하는 함수(이벤트 인지)

  // * 5. 우클릭으로 삭제하는 함수 실행
  item.addEventListener("contextmenu", removeItem);
  
  // * 1-3. 화면에 입력되도록 함
  list.appendChild(item); // item을 부모의 마지막 자식으로(위치) 붙임
  
  // * 2-5. 보낸 매개변수를 저장
  lists[listId].push(newTodo) // 배열의 item 생성 후 배열에 넣어줌
  // newTodo : id와 내가 입력한 값을 가져옴
}

// * 3. 로컬스토리지에 저장하는 함수 선언
const saveList = (aa) => { // 리스트의 아이디를 받아옴
  localStorage.setItem(aa, JSON.stringify(lists[aa]));
}

// * 1. 새 할 일을 생성하는 함수. 입력값을 받아오고 새로운 아이템을 만들어주는 함수. 
// 할 일. 오브젝트. id. 입력할 내용 등을 만드는곳. 
const createTodo = (event) => {
  event.preventDefault(); // 자동으로 새로고침되는 효과를 막아줌
  // console.log("createTodo");
  const input = document.querySelector("input"); 
  const id = uuidv4(); // uuid라이브러리를 연결하여 사용 (id를 랜덤으로 부여)
  // const text = input.value; // 입력 창 내용을 변수에 저장

  // ? newTodo
  const newTodo = {  // object 안에 집어넣을 것
    id, // 새로 만든 id값    // key: value가 같은 경우 축약 가능
    text: input.value, // 받아온 value값   // 입력 창 내용을 저장 
  }
  // console.log(newTodo.id, newTodo.text);


  // * 1-2. 입력한 내용이 목록에 추가되도록 하는 곳. item을 넣을 html 태그를 만듦
  createElement("todo", newTodo) // item을 만드는 함수 실행, 들어갈 list의 아이디는 todo
  input.value = ""; // 입력 창 비우기

  // * 3. 로컬스토리지에 저장하는 함수 실행 (로컬스토리지 업데이트)
  saveList(todo);
}

// * 4. 로컬스토리지에 저장된 내용을 불러오는 함수 정의
const loadList = () => {
  // key 단위로 불러옴
  const userTodoList = JSON.parse(localStorage.getItem("todo"));
  const userDoingList = JSON.parse(localStorage.getItem("doing"));
  const userDoneList = JSON.parse(localStorage.getItem("done"));


  if(userTodoList) {
      userTodoList.forEach((aa) => { // userTodoList에서 가져옴 (todo key값에 해당하는 value)
      createElement("todo", aa);
    });
  }
  userDoingList && userDoingList.forEach((aa) => {
    createElement("doing", aa);
  });
  userDoneList && userDoneList.forEach((aa) => {
    createElement("done", aa);
  });
};

// * 1. 아이템을 생성하는 함수 실행
form.addEventListener("submit", createTodo); 
// form의 submit = 클릭, 엔터 등 
// 무조건 새로고침이 한번 되기 때문에 preventDefault 무조건 작성

// * 2-2. 아이템이 움직일 때마다 각각 list의 id(위치)를 인식. 각 list의 위에 올라갔을 때 함수 실행
// boxes는 .list로 위에서 정의(list가 너무 많아서 헷갈릴 수 있기 때문)
boxes.forEach((box) => {
  // 각 list(li)들에 addEventListener가 부여된것
  box.addEventListener("dragover", dragOver);
})

// * 4. 로컬스토리지에 저장된 내용을 불러오는 함수 실행
loadList();

출력

  • 이미지로 대체

🔗 참고 링크 & 도움이 되는 링크






profile
공부하는 벨로그

0개의 댓글