[Vue] 6. TODO-APP 만들기



TODO-APP 만들기

11. TODO-APP 프로젝트 생성


다시 vue-cli로 todo-app라는 새로운 프로젝트를 생성해줍니다.

vue init webpack vue-todo-app
cd vue-todo-app           
npm run dev      


12. TODO-APP 퍼블리셔 작업


간단한 앱이니까 todo-list 부트스트랩 샘플을 찾아서 우선 기본적인 틀과 CSS 작업을 먼저하겠다. todoApp 컴포넌트와 목록을 루핑할 todoList 생성해주고 라우터를 수정한다.

index.html

<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, user-scalable=no">
  <title>todo-app</title>

  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap-theme.min.css">
  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
</head>

<body>
  <div id="app"></div>
</body>

</html>


components/todoApp.vue

todo App의 메인 컴포넌트이다.

<template>
  <div class="todoApp">
    <div class="form-group">
      <h1><span class="vue">Vue</span> To-Do
        <small>List</small>
      </h1>
      <form role="form">
        <input type="text" class="form-control" placeholder="해야 할 일">
      </form>
      <button type="button" class="btn btn btn-primary">Add</button>
    </div>
    <div class="todo-list">
      <!-- todoList 컴포넌트 -->
      <todoList></todoList>
    </div>
  </div>
</template>

<script>
// todoList 컴포넌트 import
import todoList from '@/components/todoList'
export default {
  name: 'todoApp',
  components: {
    'todoList': todoList
  }
}
</script>

<style scoped>
.todoApp {
  margin: auto;
  width: 500px;
}
form {
    display: inline-block;
}
.form-group {
    text-align: center;
    margin-top: 10em;
    padding-bottom: 25px;
}
.todo-list {
    width: 250px;
    text-align: left;
    margin-left: 130px;
}
a.close {
    float: right;
}
.vue {
    color: #009900;
}
</style>


components/todoList.vue

todo-list 컴포넌트이다.

<template>
  <div>
    <ul class="list-unstyled">
      <li>1. 운동하기</li>
      <li>2. JAVA</li>
      <li>3. javascript</li>
    </ul>
  </div>
</template>

<script>
  export default {
    name: 'todoList'
  };
</script>


router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import todoApp from '@/components/todoApp'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'todoApp',
      component: todoApp
    }
  ]
})


다시 화면을 띄우면 아래와 같이 뜨면 정상이다.

todo-app s1


13. TODO-APP 목록 데이터 렌더링


todoApp에서 Props로 데이터를 todoList 자식 컴포넌트로 전달해서 목록을 렌더링하겠습니다.

components/todoApp.vue 부분

동적으로 속성에 데이터 바인딩을 하기 위해서 v-bind 디렉티브를 추가합니다. <todoList v-bind:todos="todos"></todoList>

<template>
  <div class="todoApp">
    <div class="form-group">
      <h1><span class="vue">Vue</span> To-Do
        <small>List</small>
      </h1>
      <form role="form">
        <input type="text" class="form-control" placeholder="해야 할 일">
      </form>
      <button type="button" class="btn btn btn-primary">Add</button>
    </div>
    <div class="todo-list">
      <!-- todoList 컴포넌트: v-bind(디렉티브) Element 객체의 속성 동적 데이터 바인딩 -->
      <todoList v-bind:todos="todos"></todoList>
    </div>
  </div>
</template>

<script>
// todoList 컴포넌트 import
import todoList from '@/components/todoList'
export default {
  name: 'todoApp',
  // data
  data(){
    return {
      title:'',
      todos:[
        {
          title: '운동하기'
        },
        {
          title: 'JAVA'
        },
        {
          title: 'javascript'
        },
        {
          title: '영어'
        }
      ]
    }
  },
  components: {
    'todoList': todoList
  }
}
</script>


components/todoList.vue

<template>
  <div>
    <ul v-for="(todo, i) in todos" :key="todos.id" class="list-unstyled">
      `{`{i+1`}`}. `{`{todo.title`}`} <span class="close" aria-hidden="true">&times;</span>
    </ul>
  </div>
</template>

<script>
  export default {
    name: 'todoList',
    props: ['todos']
  };
</script>

우선 List 작업은 끝났다. 다시 보면 데이터가 렌더링된 화면을 볼 수 있다.

14. TODO-APP 등록 데이터 렌더링


이제 [add] 버튼을 클릭 시 등록되는 것을 구현해보겠습니다.

v-on은 Vue.js에서 지원하는 DOM조작하는 이벤트 처리역할을 한다.
v-model은 양방향 데이터 바인딩을 지원해주는 역할을 한다.

components/todoApp

<template>
  <div class="todoApp">
    <div class="form-group">
      <h1><span class="vue">Vue</span> To-Do
        <small>List</small>
      </h1>
      <form role="form">
        <input type="text" class="form-control" placeholder="해야 할 일"
            v-model="title"
		    v-on:keyup.enter="addTodo(title)">
      </form>
      <button type="button" v-on:click="addTodo(title)" class="btn btn btn-primary">Add</button>
    </div>
    <div class="todo-list">
      <!-- todoList 컴포넌트: v-bind(디렉티브) Element 객체의 속성 동적 데이터 바인딩 -->
      <todoList v-bind:todos="todos"></todoList>
    </div>
  </div> 
</template>

<script>
// todoList 컴포넌트 import
import todoList from '@/components/todoList'
export default {
  name: 'todoApp',
  // data
  data(){
    return {
      title:'',
      todos:[
        {
          title: '운동하기'
        },
        {
          title: 'JAVA'
        },
        {
          title: 'javascript'
        },
        {
          title: '영어'
        }
      ]
    }
  },
  methods:{
	addTodo(title){
	  if(title){
		this.todos.push({title:title});
		this.title = '';
      }
    }
  },
  components: {
    'todoList': todoList
  }
}
</script>


15. TODO-APP 데이터 삭제


components/todoList.vue

$emit은 del-todo 부모 TodoApp Component에 이벤트를 내보낸다.

<template>
  <div>
    <ul v-for="(todo, i) in todos" :key="todos.id" class="list-unstyled">
      <li>
        `{`{i+1`}`}. `{`{todo.title`}`} <span v-on:click="delTodo(i)" class="close" aria-hidden="true">&times;</span>
      </li>
    </ul>
  </div>
</template>

<script>
  export default {
    name: 'todoList',
    props: ['todos'],
    methods: {
      // 부모 컴포넌트에서 이벤트 핸들러를 사용하기 위해 정의
      delTodo(todo) {
        this.$emit('del-todo', todo);
      }
    }
  };
</script>


components/todoList.vue

v-on:del-todo="delTodo"는 자식 컴포넌트에서 emit한 이벤트를 부모 컴포넌트 처리를 할 수 있다. <todoList v-bind:todos=”todos” v-on:del-todo="delTodo"></todoList>

<template>
  <div class="todoApp">
    <div class="form-group">
      <h1><span class="vue">Vue</span> To-Do
        <small>List</small>
      </h1>
      <form role="form">
        <input type="text" class="form-control" placeholder="해야 할 일"
            v-model="title"
		    v-on:keyup.enter="addTodo(title)">
      </form>
      <button type="button" v-on:click="addTodo(title)" class="btn btn btn-primary">Add</button>
    </div>
    <div class="todo-list">
      <!-- todoList 컴포넌트: v-bind(디렉티브) Element 객체의 속성 동적 데이터 바인딩 -->
      <todoList v-bind:todos="todos" v-on:del-todo="delTodo"></todoList>
    </div>
  </div> 
</template>


우선은 이렇게 Vue를 이용한 todoApp을 만들어봤다.

단순한 todoApp이지만 부모/자식 컴포넌트로 구현한 이유는 테이블, 그리드, 페이징 처리 등 Vue에서 지원하는 Component를 가져다 사용 할 때 그나마 이해가 빠를 수 있다고 생각되서이다.

Vue 에 대해 개념적인 부분과 기술적인 부분 많은 블로그에 포스팅이 되어있고 정보가 많다. 그래서 React, Angular, Vue 등을 안 접해본 개발자분들이 재미를 느끼고 ‘이래서 사용하는구나’, ‘이렇게 사용하구나’가 포커스이기에 사용하는 방법에 맞춰서 진행하겠습니다.

차후 포스팅은 Restful형태로 약간의 추가작업과 지원하는 테이블, 그리드, 페이징네이션 등을 가져다 사용하는 법을 진행하겠습니다.


참고