캡틴판교님의 Vue.js 중급 강좌 - 웹앱 제작으로 배워보는 Vue.js, ES6, Vuex강의를 정리했습니다.
매일 20분 야금야금 Vue.js 중급 화이팅.
IDE: Visual Studio Code
크롬 뷰 개발자 도구: Vue.js devtools
지난 시간에 이어서 TodoList컴포넌트에서 '할 일 완료를 표시'하는 기능을 구현한다.
value값에 '할 일 완료'를 표현할 completed 속성을 넣자.
따라서 key-value 쌍으로 데이터를 넣을 때, value쪽은 문자열이 들어가게 된다.
key: inputData , value: {completed:false, item:this.newTodoItem}
객체를 문자열로 바꿔주는 JSON.stringify()를 쓰자
addTodo: function(){
var obj = {completed: false, item: this.newTodoItem}
localStorage.setItem(this.newTodoItem, JSON.stringify(obj));
this.clearInput();
},
사용자가 input에 입력한 값이 있는 경우에만 아이템을 추가하도록 if문을 넣자
addTodo: function(){
if (this.newTodoItem !== ''){
var obj = {completed: false, item: this.newTodoItem}
localStorage.setItem(this.newTodoItem, JSON.stringify(obj));
this.clearInput();
}
},
localStorage.key(i) 값으로 Item을 꺼낸다.
지금 Item은 문자열이다. 이것을 JSON으로 파싱하자.
JSON.parse(localStorage.getItem(localStorage.key(i)));
// value를 꺼낸다 , 그리고 JSON으로 파싱한다.
기존에는 JSON객체를 전부 출력한 목록이었다.
<li v-for="(todoItem, index) in todoItems" v-bind:key="todoItem" class="shadow">
<i class="checkBtn fas fa-check" v-on:click="toggleComplete"></i>
{{ todoItem }}
todoItem의 item값만 출력하도록 바꾸자.
<li v-for="(todoItem, index) in todoItems" v-bind:key="todoItem" class="shadow">
<i class="checkBtn fas fa-check" v-on:click="toggleComplete"></i>
{{ todoItem.item }}
todoItem.completed 값에 따라 checkBtnCompleted class를 넣다/뺏다를 할 수 있다.
<i class="checkBtn fas fa-check" v-bind:class="{checkBtnCompleted : todoItem.completed}"
v-on:click="toggleComplete"></i>
completed: true인 경우, "완료"이므로 아래처럼 checkBtnCompleted이 추가된다.
<i class="checkBtn fas fa-check checkBtnCompleted"
v-on:click="toggleComplete"></i>
'완료'시켜서 가로작대기를 그으면
class="checkBtn fas fa-check" 에서
class="checkBtn fas fa-check checkBtnCompleted" 로 변한다.
체크 아이콘과 글자 모두 가로선으로 지워지는 효과를 넣자
<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>
'완료' 하면, completed의 값을 기존과는 반대로 바꿔준다.
'미완료'로 바꾸면,
해당 아이템을 remove 지웠다가, 새 아이템을 추가하는 식으로 구현했다. (이 부분은 좀 아쉬운 부분이다.)
toggleComplete: function(todoItem){
todoItem.completed = !todoItem.completed;
localStorage.removeItem(todoItem.item);
localStorage.setItem(todoItem.item, JSON.stringify(todoItem));
}
<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){
console.log(todoItem, index);
localStorage.removeItem(todoItem);
this.todoItems.splice(index, 1);
},
toggleComplete: function(todoItem){
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: white;
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>
<template>
<div class="inputBox shadow">
<input type="text" v-model="newTodoItem" v-on:keyup.enter="addTodo">
<!-- <button v-on:click="addTodo">add</button> -->
<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: white;
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: white;
vertical-align: middle;
}
</style>
다음 시간에는 화면 하단의 TodoFooter 컴포넌트를 만들고, 리팩토링을 시작한다.