이 영역을 누르면 첫 페이지로 이동
자라자 블로그의 첫 페이지로 이동

자라자

페이지 맨 위로 올라가기

자라자

개발자를 준비하는 자라자의 블로그입니다.

Vanila JS로 TO DO LIST 만들기

  • 2021.11.03 17:45
  • Dev Log
01

들어가며

신촌IT연합동아리 CEOS에서 프론트엔드 스터디를 하면서 진행한 미션을 되돌아본다. 미션 주제는 Vanilla JS로 To-do list를 구현하는 것이었다. 할 일과 한 일을 구분하여 보여주고 클릭 시 반대편으로 이동하는 기능이 있다. 또 외부 폰트와 localStorage를 이용하는 것이 미션의 내용이었다.

자세한 미션의 내용은 여기서 볼 수 있다.

결과를 github Pages로 배포했는데 여기서 체험할 수 있다.

github 주소

https://github.com/BonJunKu/vanilla-todo-14th

index.html

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vanilla Todo</title>
    <link rel="stylesheet" href="style.css" />
    <script
      src="https://kit.fontawesome.com/2fdda89094.js"
      crossorigin="anonymous"
    ></script>
    <script defer type="module" src="script.mjs"></script>
  </head>

  <!-- body = waiting part + done part + add part -->
  <body>
    <main class="container">
      <!-- waiting part -->
      <section class="waiting__container">
        <img class="lion" src="./img/lion.png" alt="lion" />
        <div class="waiting__title">
          <h2>✍진행 중인 작업(<span class="waiting__count">0</span>)</h2>
        </div>
        <div class="waiting__content">
          <ul class="waiting__list"></ul>
        </div>
      </section>

      <!-- done part -->
      <section class="done__container">
        <div class="done__title">
          <h2>😆완료된 작업(<span class="done__count">0</span>)</h2>
        </div>
        <div class="done__content">
          <ul class="done__list"></ul>
        </div>
      </section>

      <!-- add part -->
      <section class="add__container">
        <input
          class="add__input"
          type="text"
          style="text-align: center"
          placeholder="새로운 할 일을 추가해주세요!"
          onfocus="this.placeholder=``; this.style.textAlign=`left`"
          onblur="this.placeholder=`새로운 할 일을 추가해주세요!`; this.style.textAlign=`center`"
        />
        <button class="add__button">+</button>
      </section>
    </main>
  </body>
</html>
```

Style.css

```css
/* Global */
:root {
  /* Color */
  --color-dark-orange: #ac5300;
  --color-white: #ffffff;
  --color-pink: #fdc7ff;
  --color-waiting: #fff5bf;
  --color-done: #fff1a0;
  --color-add: #fff5bf;

  /* Font size */
  --font-medium: 18px;
  --font-small: 16px;

  /* Size */
  --size-border-radius: 15px;
}

/* Universal tags */
* {
  box-sizing: border-box;
  font-family: 'ELAND_Choice_M';
}

/* default settings */

html,
body {
  margin: 0;
}

input,
button,
ul,
p {
  all: unset;
}

ul {
  list-style: none;
}

body {
  width: 100vw;
  height: 100vh;

  /* Center Container */
  display: flex;
  align-items: center;
  justify-content: center;

  /* Coloring */
  background-color: var(--color-dark-orange);
}

/* Typography */
@font-face {
  font-family: 'ELAND_Choice_M';
  src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts-20-12@1.0/ELAND_Choice_M.woff')
    format('woff');
  font-weight: normal;
  font-style: normal;
}
h2 {
  font-size: var(--font-medium);
}

.container {
  width: 350px;
  height: 600px;

  display: flex;
  flex-direction: column;
  align-items: stretch;

  box-shadow: 0 0 25px rgba(0, 0, 0, 0.25);
}

/* waiting part */
.waiting__container {
  background-color: var(--color-waiting);
  height: 275px;
  position: relative;
  border-top-left-radius: var(--size-border-radius);
  border-top-right-radius: var(--size-border-radius);
}
.waiting__title {
  margin: 0 15px;
}
.waiting__content {
  overflow-y: scroll;
  height: 80%;
}

span.waiting__list__item {
  padding: 0 15px;
}

.waiting__list__item .deleteButton {
  margin: 0 10px;
  display: none;
}

.lion {
  opacity: 0;
  width: 50%;
  top: 150px;
  left: 75px;
  position: absolute;
  transition: all 0.5s ease-out;
}
/* done part */
.done__container {
  background-color: var(--color-done);
  height: 275px;
}
.done__title {
  margin: 0 15px;
}
.done__content {
  overflow-y: scroll;
  height: 80%;
}
.done__list__item {
  margin: 0 15px;
}
.done__list__item .deleteButton {
  margin: 0 10px;
}

/* add part */
.add__container {
  background-color: var(--color-add);
  height: 50px;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  border-bottom-left-radius: var(--size-border-radius);
  border-bottom-right-radius: var(--size-border-radius);
}
.add__container input {
  margin: 10px 0 10px 10px;
  padding: 0 10px;
  background-color: white;
  border: solid 1px rgba(0, 0, 0, 0.25);
  border-radius: var(--size-border-radius);
  width: 270px;
}
.add__container button {
  margin: 10px 10px 10px 0;
  background-color: var(--color-dark-orange);
  width: 30px;
  height: 30px;
  text-align: center;
  border-radius: 50%;
  color: white;
}
```

script.mjs

```JavaScript
;
  localStorage.removeItem(String(id));
  render();
}

//make deleteButton visible
function appearDeleteButton() {
  const button = this.lastChild;
  button.style.display = 'inline';
  button.style.opacity = 0;
  button.style.transition = 'all 1s ease';
  setTimeout(() => {
    button.style.opacity = 1;
    this.style.color = 'brown';
    this.style.fontWeight = '900';
  });
}

//make deleteButton invisible
function disappearDeleteButton() {
  const button = this.lastChild;
  button.style.display = 'none';
  this.style.color = 'black';
  this.style.fontWeight = '400';
}

//when everything is done, LION comes out!
function summonLion() {
  lion.style.display = 'block';
  setTimeout(() => {
    lion.style.opacity = 1;
    lion.style.top = '70px';
  });
}

function vanishLion() {
  lion.style.opacity = 0;
  lion.style.display = 'none';
  lion.style.top = '100px';
}
```

피드백 받은 부분

칭찬받은 점 👍

  • 로컬스토리지에 저장을 하는 과정에서 데이터 순서가 바뀌면 안되기 때문에 인덱스를 같이 저장을 해주었는데, 이 덕분에 삭제를 할 때 O(1)로 삭제 구현을 할 수 있었다.

```JavaScript
function deleteItem() {
  let id = this.parentNode.firstChild.getAttribute('id');
  itemList.splice(id, 1);
  localStorage.removeItem(String(id));
    render();
}
```
  • functional programming을 최대한 사용한 점이 좋았다고 한다.

개선할 점 😅

  • 인라인 스타일링은 지양하는 것이 좋다고 한다.
  • prettier를 적용했는데, 적용이 안되었다(…) 알아보니 VS Code의 default editor관련 문제였다.
  • == 연산자 대신 ===연산자를 더 쓰자!!
  • 죄다 addEventListner로 처리를 했는데, 그것보다는 css에서 처리할 수 있던 점이 많았던 것 같다…
 
 
 
 

'Dev Log' 카테고리의 다른 글

온룸 파일 다운로드 관련 이슈와 해결한 방법  (0) 2022.02.11
TypeScript Object, object, {} 비교  (0) 2021.11.26
오픈소스에 기여하는 법 : MDN 문서에 기여하기  (0) 2021.11.10
크롬 글자 일그러짐 현상 해결법  (0) 2021.11.09
React Vercel로 배포 시 TypeError: Object(...) is not a function  (0) 2021.11.04

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • TypeScript Object, object, {} 비교

    TypeScript Object, object, {} 비교

    2021.11.26
  • 오픈소스에 기여하는 법 : MDN 문서에 기여하기

    오픈소스에 기여하는 법 : MDN 문서에 기여하기

    2021.11.10
  • 크롬 글자 일그러짐 현상 해결법

    크롬 글자 일그러짐 현상 해결법

    2021.11.09
  • React Vercel로 배포 시 TypeError: Object(...) is not a function

    React Vercel로 배포 시 TypeError: Object(...) is not a function

    2021.11.04
다른 글 더 둘러보기

정보

자라자 블로그의 첫 페이지로 이동

자라자

  • 자라자의 첫 페이지로 이동

검색

메뉴

  • 🏠 HOME
  • 💡 ABOUT
  • 💻 GITHUB

카테고리

  • 분류 전체보기 (91)
    • Tech Note (3)
    • Dev Log (11)
    • Study Log (11)
    • Settings (3)
    • PS (53)
      • Programmers (21)
      • BOJ (32)
    • Diary (10)

최근 글

인기 글

댓글

공지사항

아카이브

태그

  • 리액트
  • 공식문서읽기
  • ㅣ

나의 외부 링크

정보

자라자의 자라자

자라자

자라자

블로그 구독하기

  • 구독하기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. © 자라자. Designed by Fraccino.

티스토리툴바