JavaScriptでToDoListを作ってみた

JavaScript勉強の一環として，「ToDoList」を作ってみました。
classを勉強したばかりなので使ってみました。
完全独学なので，もし問題点や改善点があれば教えていただけると嬉しいです。

#仕様

+ **addボタン**を押すと，インプットエリアに入力されたテキストがリストになって追加される。
+ 追加すると，インプットエリアの文字は消える。
+ **リスト右の丸**を押すと，完了済になる(丸の色と文字色が変わる)。
+ **delate**を押すと，リストがまるごと削除される。

![todoリスト画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178942/b31e6f3e-1a5b-5e00-e468-757768f018c2.png)

#コード

####HTML

```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>To Do List</title>
   <link rel="stylesheet" href="styles/style.css">
</head>
<body>
   <div class="main-container">
      <div class="wrapper">
         <div class="title">TO DO LIST</div>
         <form class="form">
            <input class="form__text" type="text" name="text" id="form-text" size="30">
            <input class="form__add-btn" type="button" value="add" id="add-btn">
         </form>
         <div class="todo-lists">
            <ul id="ul"> 
               <!--　追加されるliのhtml構造
                  <li class="list">
                     <div class="list__check"></div>
                     <p class="list__text">インプットエリアに入力されたテキスト</p>
                     <button type="button" class="list__delate">delate</button>
                  </li>
               -->
            </ul>
         </div>
      </div>
   </div>
   <script src="scripts/main.js"></script>
</body>
</html>
```

####CSS(SCSS)
今回は特に重要ではないと思うので，折り畳んでおきます。
<details><summary>CSS(SCSS)コード</summary><div>


```scss:styles/style.scss

$cBlack: #404040;
$cGray: #9d9d9d;
$cLightBlue: #9dcbd3;
$cRed: #ff533c;
$cWhite: #ffffff;

* {
   margin: 0 auto;
}

body {
   background-color: $cLightBlue;
}

.main-container {
   width: 90vw;
   height: auto;
   max-width: 1000px;
   min-height: 90vh;
   margin: 30px auto;
   padding-bottom: 30px;
   background-color: $cWhite;
   border-radius: 30px;
   box-shadow: 0px 2px 7px 0px rgba(0, 0, 0, 0.2);
}

.wrapper {
   width: 80%;
   margin: 0 auto;
}

.title {
   padding: 30px 0;
   color: $cBlack;
   font-size: 40px;
   font-weight: 700;
   text-align: center;
}

.form {
   width: 100%;
   display: flex;
   flex-direction: column;

   &__text {
      outline: none;
      box-sizing: border-box;
      width: 100%;
      height: 45px;
      margin-bottom: 20px;
      padding: 0 15px;
      border: solid 1px $cGray;
      border-radius: 10px;
      font-size: 18px;
      color: $cBlack;
      cursor: text;
      box-shadow: 0px 2px 7px 0px rgba(0, 0, 0, 0.2);
   }
   &__add-btn {
      outline: none;
      border: none;
      width: 100%;
      height: 45px;
      padding: 0;
      margin: 0;
      background-color: $cRed;
      border-radius: 10px;
      font-size: 20px;
      color: $cWhite;
      cursor: pointer;
      box-shadow: 0px 2px 7px 0px rgba(0, 0, 0, 0.2);
   }
}

.todo-lists {
   width: 100%;
   margin-top: 40px;

   & > ul {
      list-style: none;
      padding: 0;
   }
}

.list {
   display: flex;
   align-items: center;
   padding: 15px 10px;
   box-sizing: border-box;
   border-bottom: solid 1px $cGray;

   &__check {
      flex-grow: 0;
      display: inline-block;
      width: 16px;
      height: 16px;
      background-color: $cWhite;
      margin-right: 15px;
      border: solid 1px $cGray;
      border-radius: 50%;
      transition: background-color 0.2s;
      cursor: pointer;

      &:hover {
         background-color: $cRed;
      }
   }
   &__text {
      flex-grow: 1;
      font-size: 18px;
      color: $cBlack;
   }
   &__delate {
      flex-grow: 0;
      font-size: 13px;
      color: $cGray;
      font-weight: 600;
      border: none;
      outline: none;
      cursor: pointer;
      background-color: $cWhite;
      transition: all 0.2s;

      &:hover {
         color: $cBlack;
         transform: scale(1.1);
      }
   }
   &.done {
      & .list__check {
         background-color: $cRed;
      }
      & .list__text {
         color: $cGray;
      }
   }
}

@media(min-width: 768px) {
   .title {
      font-size: 44px;
   }
   .form {
      flex-direction: row;
      justify-content: space-between;

      &__text {
         height: 60px;
         width: calc(100% - 150px);
         margin: 0;
         font-size: 24px;
      }
      &__add-btn {
         height: 60px;
         width: 100px;
         font-size: 26px;
      }
   }

   .list {
      &__check {
         width: 20px;
         height: 20px;
      }
      &__text {
         font-size: 24px;
      }
      &__delate {
         font-size: 20px;
      }
   }
   
}

@media(min-width: 1000px) {
   .wrapper {
      width: 70%;
   }
   .title {
      padding: 40px 0;
      font-size: 64px;
   }
   .list {
      &__check {
         width: 27px;
         height: 27px;
      }
   }
}
```

</div></details>

####Java Script

```javascript:scripts/main.js
document.addEventListener('DOMContentLoaded', function() {
   const ul = document.getElementById('ul');
   const addBtn = document.getElementById('add-btn');
   
   addBtn.addEventListener('click', function() {
      const todo = new ToDoList(ul);
   });
});

class ToDoList {
   constructor(ul) {
      this.ul = ul;
      const li = document.createElement('li');
      const check = document.createElement('div');
      const text = document.createElement('p');
      const button = document.createElement('button');
      this.li = li;
      this.check = check;
      this.text = text;
      this.delBtn = button;
      this._setAttr(this._getValue());
      this._addEl(this.ul);
      this._ListEvents();
   }
   _getValue() {
      this.formText = document.getElementById('form-text');
      return this.formText.value;
   }
   _setAttr(txt) {
      this.li.classList.add('list');
      this.check.classList.add('list__check');
      this.text.classList.add('list__text');
      this.text.textContent = txt;
      this.delBtn.classList.add('list__delate');
      this.delBtn.type = 'button';
      this.delBtn.textContent = 'delate';
   }
   _addEl(ul) {
      this.li.appendChild(this.check);
      this.li.appendChild(this.text);
      this.li.appendChild(this.delBtn);
      ul.appendChild(this.li);
      this.formText.value = '';
   }
   _ListEvents() {
      this.delBtn.addEventListener('click', function() {
         this.parentElement.remove();
      });
      this.check.addEventListener('click', function() {
         this.parentElement.classList.add('done');
      });
   }
}
```

#解説


```javascript:scripts/main.js
document.addEventListener('DOMContentLoaded', function() {
   const ul = document.getElementById('ul');
   const addBtn = document.getElementById('add-btn');
   
   addBtn.addEventListener('click', function() {
      const todo = new ToDoList(ul);
   });
});
```

挿入したい`ul`の取得。
addボタン`#add-btn`の取得。
addボタンが押されたら，`ToDoList`をインスタンス化し処理を実行する。

```javascript:scripts/main.js
_getValue() {
      this.formText = document.getElementById('form-text');
      return this.formText.value;
}
```

インプットエリア`#form-text`に入力されたテキストを取得する関数。
取得したテキストを`_setAttr();`で使うため，`return`で返す。

```javascript:scripts/main.js
constructor(){
//
      this._setAttr(this._getValue());
//
}
 
_setAttr(txt) {
      this.li.classList.add('list');
      this.check.classList.add('list__check');
      this.text.classList.add('list__text');
      this.text.textContent = txt;
      this.delBtn.classList.add('list__delate');
      this.delBtn.type = 'button';
      this.delBtn.textContent = 'delate';
}
```

各要素に属性等を付ける関数。
引数`txt`に`_getValue()`の結果を渡すことで，入力されたテキストを取得し代入出来る様に。


```javascript:scripts/main.js
constructor(){
//
      this._addEl(this.ul);
//
}
 _addEl(ul) {
      this.li.appendChild(this.check);
      this.li.appendChild(this.text);
      this.li.appendChild(this.delBtn);
      ul.appendChild(this.li);
      this.formText.value = '';
}
```

HTMLを組み立て，`ul`に挿入する関数。
最後にインプットエリアの中を空にする。

```javascript:scripts/main.js
_ListEvents() {
      this.delBtn.addEventListener('click', function() {
         this.parentElement.remove();
      });
      this.check.addEventListener('click', function() {
         this.parentElement.classList.add('done');
      });
}
```

delateをclickされた時と，リスト右の丸をclickされた時の処理をまとめた関数。

delateがclickされた時→押されたdelateの親要素を削除。
丸をclickされた時→classにdoneを追加し表示を変える。

#反省点，改善点
+ インプットエリアが空でもリストが作成出来てしまう。（文字数制限が出来ていない。）
+ インプットエリアにテキストを入力しそのままenterを押すと，それまでのリストも含めて全部どこかに飛んで消えてしまう。

分かり次第更新したいと思います。