6. Todo App 구현 - 할 일 삭제

freejia·2021년 10월 23일
0

캡틴판교님의 Vue.js 중급 강좌 - 웹앱 제작으로 배워보는 Vue.js, ES6, Vuex강의를 정리했습니다.
매일 20분 야금야금 Vue.js 중급 화이팅.

IDE: Visual Studio Code
크롬 뷰 개발자 도구: Vue.js devtools


TodoList 컴포넌트의 3가지 기능

  1. 할 일을 목록에 표시 [지난 포스트]
  2. 할 일 하나를 삭제 [지난 포스트]
  3. 할 일 완료 표시 [이번 포스트]

지난 시간에 이어서 TodoList컴포넌트에서 '할 일 완료를 표시'하는 기능을 구현한다.

[3. 할 일 완료 기능]

1.[TodoInput.vue] completed 속성으로 할일을 완료했는지 표시하자

value값에 '할 일 완료'를 표현할 completed 속성을 넣자.
따라서 key-value 쌍으로 데이터를 넣을 때, value쪽은 문자열이 들어가게 된다.
key: inputData , value: {completed:false, item:this.newTodoItem}

객체를 문자열로 바꿔주는 JSON.stringify()를 쓰자

    addTodo: function(){
      var obj = {completed: false, item: this.newTodoItem}
      localStorage.setItem(this.newTodoItem, JSON.stringify(obj));
      this.clearInput();
    },

사용자가 input에 입력한 값이 있는 경우에만 아이템을 추가하도록 if문을 넣자

    addTodo: function(){
      if (this.newTodoItem !== ''){
        var obj = {completed: false, item: this.newTodoItem}
        localStorage.setItem(this.newTodoItem, JSON.stringify(obj));
        this.clearInput();
      }
    },

2. [TodoList.vue] todoItem의 completed를 제외한 값만 출력하자.

localStorage의 value에 있는 문자열을 JSON으로 파싱한다.

localStorage.key(i) 값으로 Item을 꺼낸다.
지금 Item은 문자열이다. 이것을 JSON으로 파싱하자.

JSON.parse(localStorage.getItem(localStorage.key(i))); 
// value를 꺼낸다 , 그리고 JSON으로 파싱한다. 

3. template 부분에서 value값만 출력하자.

기존에는 JSON객체를 전부 출력한 목록이었다.

<li v-for="(todoItem, index) in todoItems" v-bind:key="todoItem" class="shadow">
    <i class="checkBtn fas fa-check" v-on:click="toggleComplete"></i>
    {{ todoItem }}

todoItem의 item값만 출력하도록 바꾸자.

<li v-for="(todoItem, index) in todoItems" v-bind:key="todoItem" class="shadow">
   <i class="checkBtn fas fa-check" v-on:click="toggleComplete"></i>
   {{ todoItem.item }}

4. '할 일 완료'라면 글자에 가로 선 그어서 표시하기

v-bind:class= 값에 따라 적용되는 class를 다르게 할 수 있다.

todoItem.completed 값에 따라 checkBtnCompleted class를 넣다/뺏다를 할 수 있다.

  <i class="checkBtn fas fa-check" v-bind:class="{checkBtnCompleted : todoItem.completed}" 
  v-on:click="toggleComplete"></i>

completed: true인 경우, "완료"이므로 아래처럼 checkBtnCompleted이 추가된다.

  <i class="checkBtn fas fa-check checkBtnCompleted" 
  v-on:click="toggleComplete"></i>

개발자도구 Element 탭에서 HTML 코드를 확인하자.

'완료'시켜서 가로작대기를 그으면
class="checkBtn fas fa-check" 에서
class="checkBtn fas fa-check checkBtnCompleted" 로 변한다.

체크 아이콘과 글자 모두 가로선으로 지워지는 효과를 넣자

  <i class="checkBtn fas fa-check" v-bind:class="{checkBtnCompleted: todoItem.completed}" 
 v-on:click="toggleComplete(todoItem, index)"></i>
        
  <span v-bind:class="{textCompleted: todoItem.completed}">
  {{ todoItem.item }}</span>

5. '할 일 완료'하면 completed 값을 true/false로 바꾸기

'완료' 하면, completed의 값을 기존과는 반대로 바꿔준다.
'미완료'로 바꾸면,
해당 아이템을 remove 지웠다가, 새 아이템을 추가하는 식으로 구현했다. (이 부분은 좀 아쉬운 부분이다.)

    toggleComplete: function(todoItem){
      todoItem.completed = !todoItem.completed;
      localStorage.removeItem(todoItem.item);
      localStorage.setItem(todoItem.item, JSON.stringify(todoItem));
    }

TodoList.vue 전체코드

<template>
  <div>
    <ul>
      <li v-for="(todoItem, index) in todoItems" v-bind:key="todoItem.item" class="shadow">
        <i class="checkBtn fas fa-check" v-bind:class="{checkBtnCompleted: todoItem.completed}" 
        v-on:click="toggleComplete(todoItem, index)"></i>
        <span v-bind:class="{textCompleted: todoItem.completed}">{{ todoItem.item }}</span>
      <span class="removeBtn" v-on:click="removeTodo(todoItem, index)">
        <i class="fas fa-trash-alt"></i>
      </span>
      </li>
    </ul>
  </div>
</template>

<script>

export default {
  data: function(){
    return {
      todoItems: []
    }
  },
  methods: {
    removeTodo: function(todoItem, index){
      console.log(todoItem, index);
      localStorage.removeItem(todoItem);
      this.todoItems.splice(index, 1);
    },
    toggleComplete: function(todoItem){
      todoItem.completed = !todoItem.completed;
      localStorage.removeItem(todoItem.item);
      localStorage.setItem(todoItem.item, JSON.stringify(todoItem));
    }
  },
  created: function(){
    if (localStorage.length > 0) {
      for(var i = 0; i< localStorage.length; i++){
        if (localStorage.key(i) !== 'loglevel:webpack-dev-server') {
          this.todoItems.push(JSON.parse(localStorage.getItem(localStorage.key(i))));
        }
      }
    }
  }
}
</script>

<style scoped>
ul {
  list-style-type: none;
  padding-left: 0px;
  margin-top: 0;
  text-align: left;
}
li {
  display: flex;
  min-height: 50px;
  height: 50px;
  line-height: 50px;
  margin: 0.5rem 0;
  padding: 0 0.9rem;
  background: white;
  border-radius: 5px;
}
.checkBtn {
  line-height: 45px;
  color: #62acde;
  margin-right: 5px;
}
.checkBtnCompleted {
  color: #b3adad;
}
.textCompleted {
  text-decoration: line-through;
  color: #b3adad;
}
.removeBtn {
  margin-left: auto;
  color: #de4343;
}
</style>

TodoInput.vue 전체코드

<template>
  <div class="inputBox shadow">
    <input type="text" v-model="newTodoItem" v-on:keyup.enter="addTodo">
    <!-- <button v-on:click="addTodo">add</button> -->
    <span class="addContainer" v-on:click="addTodo">
      <i class="fas fa-plus addBtn"></i>
    </span>
  </div>
</template>

<script>
export default {
  data: function(){
    return {
      newTodoItem: ""
    }
  },
  methods: {
    addTodo: function(){
      if (this.newTodoItem !== ''){
        var obj = {completed: false, item: this.newTodoItem}
        localStorage.setItem(this.newTodoItem, JSON.stringify(obj));
        this.clearInput();
      }
    },
    clearInput: function(){
      this.newTodoItem = '';
    }
  }
}
</script>

<style scoped>
input:focus {
  outline: none;
}
.inputBox {
  background: white;
  height: 50px;
  line-height: 50px;
  border-radius: 5px;
}
.inputBox input {
  border-style: none;
  font-size: 0.9rem;
}
.addContainer {
  float: right;
  background: linear-gradient(to right, #6478fb, #8763fb);
  display: block;
  width: 3rem;
  border-radius: 0 5px 5px 0;
}
.addBtn {
  color: white;
  vertical-align: middle;
}
</style>

다음 시간에는 화면 하단의 TodoFooter 컴포넌트를 만들고, 리팩토링을 시작한다.

profile
코딩 리딩 라이딩💛

0개의 댓글