vue.js와 vue material을 이용한
todolist 앱 리팩토링
todolist 앱 리팩토링
리팩토링 전의 앱의 구현 내용은 아래의 포스트로 이동해주세요.
https://goddino.tistory.com/90
예제는 인프론의 Vue.js 끝장내기 강의를 듣고 참조하여 공부한 내용입니다.
TodoList 앱화면
리팩토링 작업 과정:
하위 컴포넌트의 훅, 데이터, 메소드를 상위 컴포넌트로 옮긴다.
TodoList.vue 파일(할일 목록 표시)
1. TodoList.vue에서 create lifecycle hook과 data todos를 App.vue로 올린다.
2. App.vue에서 TodoList.vue로, 데이터 todos를 props를 통해 넘겨준다.
TodoInput.vue 파일(할일 추가 표시)
3. TodoInput.vue에서 클릭이벤트 add 메소드를 App.vue로 emit.event를 통해 올린다.
4. 위 메소드로 추가된 obj를 todos 배열에 추가하여 바로 list에 자동생성 한다.
TodoList.vue 파일(할일 삭제)
5. TodoList.vue에서 클릭이벤트 remove 메소드를 App.vue로 emit.event를 통해 올린다.
TodoList.vue 파일(할일 완료)
6. TodoList.vue에서 클릭이벤트 toggle 메소드를 App.vue로 emit.event를 통해 올린다.
TodoFooter.vue 파일(할일 모두 삭제)
7. TodoFooter.vue에서 클릭이벤트 clear 메소드를 App.vue로 emit.event를 통해 올린다.
하위 컴포넌트의 훅, 데이터, 메소드를 상위 컴포넌트로 옮긴다.
TodoList.vue 파일(할일 목록 표시)
1. TodoList.vue에서 create lifecycle hook과 data todos를 App.vue로 올린다.
2. App.vue에서 TodoList.vue로, 데이터 todos를 props를 통해 넘겨준다.
TodoInput.vue 파일(할일 추가 표시)
3. TodoInput.vue에서 클릭이벤트 add 메소드를 App.vue로 emit.event를 통해 올린다.
4. 위 메소드로 추가된 obj를 todos 배열에 추가하여 바로 list에 자동생성 한다.
TodoList.vue 파일(할일 삭제)
5. TodoList.vue에서 클릭이벤트 remove 메소드를 App.vue로 emit.event를 통해 올린다.
TodoList.vue 파일(할일 완료)
6. TodoList.vue에서 클릭이벤트 toggle 메소드를 App.vue로 emit.event를 통해 올린다.
TodoFooter.vue 파일(할일 모두 삭제)
7. TodoFooter.vue에서 클릭이벤트 clear 메소드를 App.vue로 emit.event를 통해 올린다.
App.vue
<template>
<div id="app">
<TodoHeader></TodoHeader>
<TodoInput v-on:addOne="addFn"></TodoInput>
<TodoList v-bind:propsdata="todos"
v-on:removeOne="removeFn"
v-on:toggleOne="toggleFn"></TodoList>
<TodoFooter v-on:clearOne="clearFn"></TodoFooter>
</div>
</template>
<script>
import TodoHeader from './components/TodoHeader'
import TodoInput from './components/TodoInput'
import TodoList from './components/TodoList'
import TodoFooter from './components/TodoFooter'
export default {
data: function (){
// TodoList에서 가져옴 -> TodoList에 props로 내림
return { todos : [] }
},
methods: {
// TodoInput에서 $emit.event 가져옴
addFn(todoItem){
//var obj = { completed: false, item: this.doItem };
var obj = { completed: false, item: todoItem };
//localStorage.setItem(this.doItem, JSON.stringify(obj));
localStorage.setItem(todoItem, JSON.stringify(obj));
//obj를 todos에 추가 (더이상 새로고침하지 않아서 아래 리스트에 자동생성)
//todos에서 list와 input에서 가져온 것을 todos 하나로 관리
this.todos.push(obj);
},
// TodoList에서 $emit.event 가져옴
removeFn(todo, index){
//localStorage.removeItem(todo); todo에 객체 전체가 들어오므로,
//화면에서는 삭제가 되어도, localstorage에서는 안없어짐
//todo.item으로 key 값을 정확하게 지울 수 있음
localStorage.removeItem(todo.item);
this.todos.splice(index, 1);
},
// TodoList에서 $emit.event 가져옴
toggleFn(todo, index){
//todo.completed = !todo.completed;
this.todos[index].completed = !this.todos[index].completed
//localstorage 업데이트
localStorage.removeItem(todo.item);
localStorage.setItem(todo.item, JSON.stringify(todo));
},
clearFn(){
localStorage.clear();
console.log(this.todos);
this.todos = []; //this.todos = '' or null 아님
}
},
// TodoList에서 가져옴
created() {
if (localStorage.length > 0) {
for (let i = 0; i < localStorage.length; i++) {
if (localStorage.key(i) !== 'loglevel:webpack-dev-server') {
console.log(localStorage.getItem(localStorage.key(i)));
this.todos.push(JSON.parse(localStorage.getItem(localStorage.key(i))));
}
}
}
},
components: {
TodoHeader,
TodoInput,
TodoList,
TodoFooter
}
}
</script>
<style>
body {
text-align: center;
background-color: #393D49;
max-width: 800px;
width: 100%;
}
.md-layout-item {
padding: 0 5px;
}
</style>
TodoHeader.vue
(리팩토링 전과 동일)
<template>
<div class="header">
<span class="md-headline">Todolist</span>
</div>
</template>
<script>
export default {}
</script>
<style>
.header {
padding: 30px 0 20px;
}
</style>
TodoInput.vue
<template>
<div>
<div class="md-layout" style="margin: 0.5rem; color: #fff !important;">
<div class="md-layout-item md-size-90">
<md-field>
<label>Things To Do</label>
<md-input v-model="doItem" @keyup.enter="addTodo"></md-input>
</md-field>
</div>
<div class="md-layout-item md-size-10" @click="addTodo">
<i class="fas fa-plus-circle addBtn"></i>
</div>
</div>
</div>
</template>
<script>
export default {
data: function () {
return {doItem: ''}
},
methods: {
addTodo() {
if (this.doItem) { // this.$emit('이벤트이름', 인자1, 인자2);
this.$emit('addOne', this.doItem);
this.clearInput();
}
},
clearInput() {
this.doItem = '';
}
}
}
</script>
<style>
.md-field,
.md-focused,
.md-input,
.md-textarea,
label {
background: #365FD9 !important;
border-style: none;
border-radius: 5px;
margin: 0 0 5px 0 !important;
color: #fff !important;
-webkit-text-fill-color: #ddd !important;
}
.addBtn {
vertical-align: middle;
margin-top: 12px;
font-size: 24px;
cursor: pointer;
}
</style>
TodoList.vue
<template>
<div>
<ul>
<li v-for="(todo, index) in propsdata" v-bind:key="todo">
<div>
<i class="fas fa-check checkBtn"
@click="toggleFn(todo, index)"
v-bind:class="{checkBtnCompleted: todo.completed}"></i>
<span @click="toggleFn(todo, index)"
:class="{textCompleted: todo.completed}">{{todo.item}}</span>
</div>
<span class="removeBtn" @click="removeFn(todo, index)">
<i class="far fa-trash-alt"></i>
</span>
</li>
</ul>
</div>
</template>
<script>
export default {
props: ['propsdata'], //todos를 App.vue에 옮겨가고, props로 받는다. todos -> propsdata
methods: {
removeFn(todo, index) {
this.$emit('removeOne', todo, index );
},
toggleFn(todo, index) {
this.$emit('toggleOne', todo, index);
}
}
}
</script>
<style>
ul {
list-style-type: none;
padding-left: 0;
margin-top: 0;
text-align: left;
}
li {
display: flex;
min-height: 50px;
height: 50px;
line-height: 50px;
margin: 1rem;
padding: 0 0.9rem;
background: #4872F0;
border-radius: 5px;
justify-content: space-between;
}
span {
cursor: pointer;
color: #fff !important;
}
.checkBtn {
line-height: 45px;
color: #F0C148;
margin-right: 20px !important;
cursor: pointer;
}
.checkBtnCompleted {
text-decoration: line-through;
}
.textCompleted {
text-decoration: line-through;
}
.removeBtn {
cursor: pointer;
}
</style>
TodoFooter.vue
<template>
<div class="clearAllList">
<md-button class="clearAllBtn" @click="clearAll">clear all</md-button>
</div>
</template>
<script>
export default {
methods: {
clearAll() {
this.$emit('clearOne');
}
}
}
</script>
<style>
.clearAllBtn {
background-color: #F2B705 !important;
}
</style>
반응형
'개발 > React' 카테고리의 다른 글
[vue] vue 모달창, 다이얼로그 기능 구현하기(ft. slot) (0) | 2020.11.23 |
---|---|
[vue] vue.js Post 폼 데이터 api 전송하기(axios, 유효성 검사) (0) | 2020.11.22 |
[vue] vue.js로 todolist 투두리스트앱 만들기(리팩토링 전) (0) | 2020.11.20 |
[vue] vue.js에서 axios 사용하여 서버 통신(vue material 테이블에 데이터 뿌리기) (0) | 2020.11.18 |
[vue] vue.js 컴포넌트 생성(컴포넌트로 쪼개기) (0) | 2020.11.15 |
댓글