[Vue-Project] Todo-App

2022. 4. 1. 23:28Vue

1. index.html 

getbootstrap.com 들어가서 css link 복사해서 연결해준다.

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">

 

 

2.컴포넌트 연결하기 / v-for문 돌리기

components  파일에서 Todo.vue 컴포넌트 만들고  연결해준다.

// App.vue 부모
<template>
  <div id="app" class="container">
    <h1 class="text-center">Todo App</h1>
    <input type="text" class="w-100 p-2" placeholder="Type todo">
    <hr>
    
    <Todo v-for="todo in todos"
          :key="todo.id">
    </Todo>
  </div>
</template>

<script>
import Todo from "@/components/Todo"
export default {
  components: {Todo},
  data() {
    return {
      todos: [
        {id: 1, text: 'study hard', checked: true},
        {id: 2, text: 'buy a car', checked: false},
      ]
    }
  },
}
</script>
// Todo.vue 자식
<template>
  <div>
    <input type="checkbox">
    <span class="ml-3">Buy a car</span>
  </div>
</template>

<script>
export default {
  name: "Todo",
}
</script>

v-for문을 도는데 Buy a car가 두번나온다 ㅇ-ㅇ ,,,;;;;;옴마마

 

 

:todo="todo" 로 하고 props에 todo로 받아와도 되는데 구분을 하기 위해 나는 :todoList로 바인딩을 해주었다.

App.vue 에서 v-for문을 도는데 Todo.vue (자식) 컴포넌트에  데이터를 넘겨 줘야한다. 그래서 props로 데이터를 전달받아서 뿌려줌 !

체크 박스도 전달 받아야겠지???? 

=>  :checked="todoList.checked" 해주고 true면 체킹이 되어진다.

 

 

 

 

 

3. @keyup.enter 이벤트 추가 하기

<template>
  <div id="app" class="container">
    <h1 class="text-center">Todo App</h1>
    <input type="text"
           class="w-100 p-2"
           placeholder="Type todo"
           @keyup.enter="addTodo">
    <hr>
    <Todo v-for="todo in todos"
          :key="todo.id"
          :todoList="todo">
    </Todo>
  </div>
</template>

<script>
import Todo from "@/components/Todo"
export default {
  components: {Todo},
  data() {
    return {
      todos: [
        {id: 1, text: 'study hard', checked: true},
        {id: 2, text: 'buy a car', checked: false},
      ]
    }
  },
  methods: {
    addTodo(e) {
      this.todos.push(
      {id: Math.random(),
        text: e.target.value,
        checked: false}
      )
    },
  }
}
</script>

 

 

 

 

4. input 에 글쓰고 난 후 비워주기

<template>
  <div id="app" class="container">
    <h1 class="text-center">Todo App</h1>
    <input type="text"
           v-model="clearText"
           class="w-100 p-2"
           placeholder="Type todo"
           @keyup.enter="addTodo">
    <hr>
    <Todo v-for="todo in todos"
          :key="todo.id"
          :todoList="todo">
    </Todo>
  </div>
</template>

<script>
import Todo from "@/components/Todo"
export default {
  components: {Todo},
  data() {
    return {
      clearText: '',
      todos: [
        {id: 1, text: 'study hard', checked: true},
        {id: 2, text: 'buy a car', checked: false},
      ]
    }
  },
  methods: {
    addTodo(e) {
      this.todos.push({
        id: Math.random(),
        text: e.target.value,
        checked: false
      });
      this.clearText = ''
    },
  }
}
</script>

 

input 에 v-model 써주고, data에 넣고, @keyup.enter 메소드 안에서 push 한 다음, this.clearText= ''로 초기화 시키기

 

 

 

 

5. emit으로 값 전달해주기

todoList.checked 출력된 값이 있고 체크박스를 클릭했다 안했다하면 true 에서 false로 값이 바뀌지 않는다.

그래서 이것을 바뀌도록 하는 작업이 필요하다.

// Todo.vue 자식컴포넌트
<template>
  <div>
    {{ todoList.checked}}
    <input type="checkbox"
           :checked="todoList.checked"
           @change="toggleCheckbox">
    <span class="ml-3">{{ todoList.text }}</span>
  </div>
</template>

<script>
export default {
  name: "Todo",
  props: {
    todoList: {
      type: Object,
      required: true,
    }
  },
  methods: {
    toggleCheckbox(e) {
      this.$emit('toggle-checkbox', {
        id: this.todoList.id,
        checked: e.target.checked
      })
    }
  }
}
</script>

@change="toggleCheckbox" 체인지 이벤트를 만들고 부모한테 값을 넘겨주기

객체로 value값을 넘긴거라서 App.vue에서는 구조분해 할당으로 { id, checked }로 value값을 받아 와야 한다.

$emit으로 보낸 것을 부모에서는 @toggle-checkbox 로 기입 

>> 자꾸 : 이걸로 쓰는 데 @ 쓰기!!!!!!!!!!!!!!!!!!!!!

// App.vue 부모
<template>
  <div id="app" class="container">
    <h1 class="text-center">Todo App</h1>
    <input type="text"
           v-model="clearText"
           class="w-100 p-2"
           placeholder="Type todo"
           @keyup.enter="addTodo">
    <hr>
    <Todo v-for="todo in todos"
          :key="todo.id"
          :todoList="todo"
          @toggle-checkbox="toggleCheckbox">
    </Todo>
  </div>
</template>

<script>
import Todo from "@/components/Todo"
export default {
  components: {Todo},
  data() {
    return {
      clearText: '',
      todos: [
        {id: 1, text: 'study hard', checked: true},
        {id: 2, text: 'buy a car', checked: false},
      ]
    }
  },
  methods: {
    addTodo(e) {
      this.todos.push(
      {id: Math.random(),
        text: e.target.value,
        checked: false}
      );
      this.clearText = ''
    },
    toggleCheckbox({id, checked}) {
      const index = this.todos.findIndex( todo => {
        return todo.id === id;
      })
      this.todos[index].checked = checked;
    }
  }
}
</script>

 

id랑 같은거 찾아서 index 를 알아내고, 그 인덱스에서 checked 되어있는지도 값 받아와서 ...

checkbox 클릭하면 false > true / true > false로 변경된다.

 

 

 

 

6. checkbox true 이면 밑줄 그어 주기

:class, :style 바인딩

// todo.vue
<template>
  <div>
    {{ todoList.checked}}
    <input type="checkbox"
           :checked="todoList.checked"
           @change="toggleCheckbox">
    <span class="ml-3"
          :class="todoList.checked ? 'text-muted' : ''"
          :style="todoList.checked ? 'text-decoration:line-through' : ''">
      {{ todoList.text }}
    </span>
  </div>
</template>

<script>
export default {
  name: "Todo",
  props: {
    todoList: {
      type: Object,
      required: true,
    }
  },
  methods: {
    toggleCheckbox(e) {
      this.$emit('toggle-checkbox', {
        id: this.todoList.id,
        checked: e.target.checked
      })
    }
  }
}
</script>

 

 

 

7. delete 버튼 추가

// Todo.vue
<template>
  <div class="mb-2 d-flex">
    <div>
      <input type="checkbox"
             :checked="todoList.checked"
             @change="toggleCheckbox">
    </div>

    <span class="ml-3 flex-grow-1"
          :class="todoList.checked ? 'text-muted' : ''"
          :style="todoList.checked ? 'text-decoration:line-through' : ''">
      {{ todoList.text }}
    </span>
    <button class="btn btn-danger btn-sm"
            @click="clickDelete">delete
    </button>
  </div>
</template>

<script>
export default {
  name: "Todo",
  props: {
    todoList: {
      type: Object,
      required: true,
    }
  },
  methods: {
    toggleCheckbox(e) {
      this.$emit('toggle-checkbox', {
        id: this.todoList.id,
        checked: e.target.checked
      })
    },
    clickDelete() {
      this.$emit('click-delete', this.todoList.id)
    }
  }
}
</script>
// App.vue
<template>
  <div id="app" class="container">
    <h1 class="text-center">Todo App</h1>
    <input type="text"
           v-model="clearText"
           class="w-100 p-2"
           placeholder="Type todo"
           @keyup.enter="addTodo">
    <hr>
    <Todo v-for="todo in todos"
          :key="todo.id"
          :todoList="todo"
          @toggle-checkbox="toggleCheckbox"
          @click-delete="clickDelete">
    </Todo>
  </div>
</template>

<script>
import Todo from "@/components/Todo"
export default {
  components: {Todo},
  data() {
    return {
      clearText: '',
      todos: [
        {id: 1, text: 'study hard', checked: true},
        {id: 2, text: 'buy a car', checked: false},
      ]
    }
  },
  methods: {
    addTodo(e) {
      this.todos.push(
      {id: Math.random(),
        text: e.target.value,
        checked: false}
      );
      this.clearText = ''
    },
    toggleCheckbox({id, checked}) {
      const index = this.todos.findIndex( todo => {
        return todo.id === id;
      })
      this.todos[index].checked = checked;
    },
    clickDelete(id) {
      const index = this.todos.findIndex( todo => {
        return todo.id === id
      });
      this.todos.splice(index, 1)
    }
  }
}
</script>

filter 메소드 사용 하는 경우

clickDelete(id) {
  // const index = this.todos.findIndex( todo => {
  //   return todo.id === id
  // });
  // this.todos.splice(index, 1)
  this.todos = this.todos.filter(todo => todo.id !== id)
}

 

 

 

 

 

 

 

'Vue' 카테고리의 다른 글

Bootstrap 적용하기  (0) 2022.04.13
Vue Router - prefetch, Lazy Loading(지연된 로딩)  (0) 2022.04.07
[Vue] Props Emit 부모 자식 간에 데이터 주고 받기  (3) 2022.03.18
[Vue] Slot  (0) 2022.03.17
[Vue] 인코딩 / 디코딩  (0) 2022.03.15