Todo App
컴포넌트 생성 및 등록
- todoapp 프로젝트 생성
npm install -g @vue/cli
vue create todoapp
cd todoapp
npm run serve
- 'TodoHeader.vue', 'TodoInput.vue', 'TodoList.vue', 'TodoFooter.vue' 파일 생성
|- /public
|- favicon.ico
|- index.html
|- /src
|- /components
+ |- /TodoHeader.vue
+ |- /TodoInput.vue
+ |- /TodoList.vue
+ |- /TodoFooter.vue
|- App.vue
|- main.js
- 'App.vue' 수정
/* App.vue */
<template>
<div id="app">
<TodoHeader></TodoHeader>
<TodoInput></TodoInput>
<TodoList></TodoList>
<TodoFooter></TodoFooter>
</div>
</template>
<script>
import TodoHeader from './components/TodoHeader.vue';
import TodoInput from './components/TodoInput.vue';
import TodoList from './components/TodoList.vue';
import TodoFooter from './components/TodoFooter.vue';
export default {
components:{
'TodoHeader': TodoHeader,
'TodoInput' : TodoInput,
'TodoList' : TodoList,
'TodoFooter' : TodoFooter
}
}
</script>
<style>
body{text-align:center;background:#f5f5f5;font-family: 'Ubuntu', sans-serif;}
input{border-style:groove;width:200px;}
button{border-style:groove;}
.shadow{box-shadow:5px 10px 10px rgba(0,0,0,0.03);}
</style>
파비콘, 아이콘, 폰트, 반응형 태그 설정
파비콘 생성
웹폰트 설정
<!-- index.html -->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>todoapp</title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Ubuntu" rel="stylesheet">
</head>
TodoHeader 컴포넌트 구현
/* TodoHeader.vue */
<template>
<header>
<h1>TODO</h1>
</header>
</template>
<style scoped>
h1{color:#2f3b52;font-weight:900;margin:2.5rem 0 1.5rem;}
</style>
TodoInput 컴포넌트 구현
/* TodoInput.vue */
<template>
<div class="inputBox shadow">
<input type="text" v-model="newTodoItem" v-on:keyup.enter="addTodo">
<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:#fff;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:#fff;vertical-align:middle;}
</style>
TodoList 컴포넌트 구현
/* 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){
localStorage.removeItem(todoItem);
this.todoItems.splice(index,1);
},
toggleComplete:function(todoItem, index){
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:#fff;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>
TodoFooter 컴포넌트 구현
/* TodoFooter.vue */
<template>
<div class="clearAllContainer">
<span class="clearAllBtn" v-on:click="clearTodo">clear all</span>
</div>
</template>
<script>
export default {
methods:{
clearTodo:function(){
localStorage.clear();
}
}
}
</script>
<style scoped>
.clearAllContainer{width:8.5rem;height:50px;line-height:50px;background-color:#fff;border-radius:5px;margin:0 auto;}
.clearAllBtn{color:#e20303;display:block;}
</style>