Vue.js

Vue.js 3.0 STEP 5 - TodoList

IT의 큰손 2024. 1. 25. 13:12
728x90

★ TodoList

  • 할일을 적고 해당 사항들을 수행해 나가는 List
  • Step1 ~ Step4에 대한 내용을 가지고 해당 기능을 개발

 

1. 기본 UI 개발

  • 큰 틀 잡기
<style>
        body { margin : 0; padding : 0; font-family: sans-serif; }
        .title { text-align: center; font-weight: bold; font-size: 20pt; }
        .todo-done { text-decoration:  line-through; }
        .container { padding:10px 10px 10px 10px; }
        .panel-borderless { border : 0; box-shadow: none; }
        .pointer { cursor : pointer; } 
    </style>
</head>
<body>
    <div id="app" class="container">
        <div class="card card-body bg-light">
            <div class="title">:: Todolist App</div>
        </div>
        <div class="card card-default card-borderless">
            <div class="card-body">
                
                <!-- 본문 내용 삽입 -->
                
            </div>
        </div>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
    
    </script>
</body>
  • 본문 내용 삽입
<div class="row mb-3">
    <div class="col">
        <div class="input-group">
            <input id="msg" type="text" class="form-control" name="msg" placeholder="할일을 여기에 입력하세요!" />
            <span class="btn btn-primary input-group-addon">추가</span> 
        </div> 
    </div>
</div>

<div class="row">
    <div class="col">
        <ul class="list-group">
            <li class="list-group-item list-group-item-success">
                <span class="todo-done pointer">할일 1 (완료)</span>
                <span class="float-end badge bg-secondary pointer">삭제</span>
            </li>
            <li class="list-group-item">
                <span class="pointer">할일2</span>
                <span class="float-end badge bg-secondary pointer">삭제</span>
            </li>
            <li class="list-group-item">
                <span class="pointer">할일3</span>
                <span class="float-end badge bg-secondary pointer">삭제</span>
            </li>
        </ul>
    </div>
</div>

 

 

2. 데이터와 메서드 정의

     [ 데이터 ]
todo 텍스트 박스에 사용자가 입력하는 내용을 받아내기 위한 data 입니다.
todolist 추가한 todo 들의 목록, todo 한 건은 다음과 같습니다.
id todo 한 건의 고유 키, 이 예제에서는 timestamp를 이용합니다.
todo todo 내용
completed 완료 여부(true, false)
    [ 메서드 ]
addTodo 텍스트 박스에 사용자가 입력하는 내용을 받아내기 위한 data 입니다.
deleteTodo 추가한 todo 들의 목록, todo 한 건은 다음과 같습니다.
toggleCompleted todo 한 건의 고유 키, 이 예제에서는 timestamp를 이용합니다.

 

  • 정의한 데이터와 메서드를 토대로 Vue 인스턴스 코드를 작성하면
var ts = new Data().getTime()
    var vm = Vue.createApp({
        name : "App",
        data() {
            return {
                todo : "",
                todolist : [
                    { id : ts, todo:"Vue 공부하기", completed : false},
                    { id : ts+1, todo:"Vue 실습하기", completed : true},
                    { id : ts+2, todo:"Toy Project", completed : false},
                    { id : ts+3, todo:"Spring Boot 공부", completed : false},
                ]
            }
        },
        methods : {
            addTodo() {
                if (this.todo.length >= 2) {
                    this.todolist.push({ id : new Date().getTime(),
                        todo: this.todo, completed: false });
                    this.todo = ""
                }
            },
            deleteTodo(id) {
                let index = this.todolist.findIndex((item)=> id === item.id);
                this.todolist.splice(index, 1);
            },
            toggleCompleted(id) {
                let index = this.todolist.findIndex((item)=> id === item.id);
                this.todolist[index].completed = !this.todolist[index].completed;
            }
        }
    }).mount("#app")

 

 

3. 템플릿 작성

<div id="app" class="container">
    <div class="card card-body bg-light">
        <div class="title">:: Todolist App</div>
    </div>
    <div class="card card-default card-borderless">
        <div class="card-body">
            <!-- 이곳에 삽입 될 예쩡 -->
            <div class="row mb-3">
                <div class="col">
                    <div class="input-group">
                        <input id="msg" type="text" class="form-control" name="msg" placeholder="할일을 여기에 입력하세요!" 
                         v-model.trim="todo" @keyup.enter="addTodo" />
                        <span class="btn btn-primary input-group-addon" @click="addTodo">추가</span> 
                    </div> 
                </div>
            </div>

            <div class="row">
                <div class="col">
                    <ul class="list-group">
                        <li v-for="todoitem in todolist" :key="todoitem.id"
                            class="list-group-item"
                            :class="{ 'list-group-item-success' : todoitem.completed }"
                            @click="toggleCompleted(todoitem.id)" >
                            <span class="pointer" :class="{ 'todo-done' : todoitem.completed }">
                                {{todoitem.todo}} {{ todoitem.completed ? "(완료)" : ""}}
                            </span>
                            <span class="float-end badge bg-secondary pointer"
                                @click.stop="deleteTodo(todoitem.id)">삭제</span>
                    </ul>
                </div>
            </div>
        </div>
    </div>
</div>

 

 

4. 설명

4.1 5행~

  • 할일(todo)을 사용자로부터 입력받을 수 있게 v-model 디렉티브를 이용해, 양방향으로 바인딩.
  • 앞뒤 공백 문자를 자동으로 제거할 수 있도록 .trim 수식어를 지정.
  • 입력 후, enter키를 누르면, addTodo() 메서드를 실행해 한 건의 todo가 추가.
  • 동일하게, 추가 버튼을 클릭하여도, addTodo() 메서드를 실행

4.2 15행~

  • <li> 요소는 todolist 내부의 아이템 수만큼 반복 렌더링해야 하므로, v-for 디렉티브를 사용.
  • :key 특성은 반드시 고유 키를 부여해야 하므로, id 필드를 부여하도록 한다.
  • <li> 요소는 완료 여부에 따라 다르게 스타일링 되어야 하므로, 달라질 스타일로 구분하여
  • 정적인 스타일 : class="list-group-item", 달라질 스타일 : true,false 값을 가지는 객체이므로 -> :class 로 바인딩

4.3 18행, 23행

  • 완료를 토글 처리하는 이벤트와 삭제 처리하는 이벤트를 등록
  • 삭제 처리 : 이벤트 .stop 수식어를 등록했음에 유의. 이 수식어를 작성하지 않고 삭제 버튼을 클릭하면 이벤트가 버블링하면서 완료 토글 이벤트까지 실행되면서 오류가 발생한다.

 

5. 실행 화면

 

6. 마무리

  • 템플릿 코드의 작성보다 화면 시안을 반영해 data와 data의 변경을 일으키는 메서드의 작성을 먼저 진행해야한다.
화면 시안 -> data 정의 -> 메서드 정의 -> 템플릿 작성

 

728x90