컴포넌트 통신하지 않은 Todolist 보러 가기 ▼
전에 올린 포스팅은 컴포넌트간 통신이 되지않아 데이터 교류가 되지 않는 오류가 있었다.
오류를 해결하기 위해 v-bind와 v-on을 이용하여 컴포넌트간 통신이 이루어지게 해보자.
*주석으로 달아놓은 번호 따라가면 컴포넌트 통신 큰 줄기 이해 가능
1. App.vue
<template>
<div id="app">
<Header></Header>
<Input v-on:addTodoItems="addOneItem"></Input>
<!-- 3. v-bind:내려보낼 props 속성 이름="현재 위치의 컴포넌트 데이터 속성" -->
<List v-bind:propsdata="todoItems" v-on:removeOneItem="removeItem"></List>
<Footer v-on:removeAllItems="clearAllItems"></Footer>
</div>
</template>
<script>
import Header from './components/Header'
import Input from './components/Input'
import List from './components/List'
import Footer from './components/Footer'
export default {
data(){
return{
// 2. 모든 components에서 사용되는 데이터 정의
todoItems : []
}
},
//1. life cycle중에서 가장 처음 실행되는 creation단계의 hook을 list.vue에서 App.vue로 옮겨옴
created(){
if(localStorage.length > 0){
for(let i=0; i < localStorage.length; i++){
if(localStorage.key(i) !== "loglevel:webpack-dev-server"){
this.todoItems.push(JSON.parse(localStorage.getItem(localStorage.key(i))));
}
}
}
},
methods : {
removeItem(todoItem, index){
localStorage.removeItem(todoItem.title);
this.todoItems.splice(index, 1);
},
addOneItem(Item){
const todoItem = {
title : Item,
completed : false
}
localStorage.setItem(todoItem.title, JSON.stringify(todoItem));
this.todoItems.push(todoItem); // 추가
},
clearAllItems(){
localStorage.clear();
//localStorage도 삭제해주고 배열도 삭제해줘야함 *
this.todoItems = [];
}
},
components : {
Header,
Input,
List,
Footer
}
}
</script>
<style>
html body {
width : 100%;
height : 100%;
text-align : center;
}
#app {
margin : 0 auto;
padding : 1%;
width : 40%;
border : 1px solid black;
}
</style>
- v-bind:내려보낼 프롭스 속성 이름="현재 위치의 컴포넌트 데이터 속성"
: 오타주의, 적용되는 속성 위치 파악 중요
- Item 추가 (addOneItem method)
: 컴포넌트간 데이터 통신이 목적이기 때문에 localStorage에 Item을 추가해주는 코드만 App.vue로 이동
- List 전체 삭제 (clearAllItems method)
: localStorage 데이터만 삭제하는 게 아닌 배열도 비워줘야 view에서 리스트가 삭제된게 확인됨
2. Input.vue
<template>
<div>
<input type="text" v-model="newTodoItem" @keyup.enter="addTodoItem"/><button @click="addTodoItem">click</button>
<modal v-if="showModal" @close="showModal=false">
<template v-slot:header><i class="closeModal fas fa-window-close" @click="closeModalBtn"></i></template>
<template v-slot:body>List를 입력해주세요!</template>
</modal>
</div>
</template>
<script>
import modal from './modal'
export default {
data(){
return {
newTodoItem : "",
showModal : false
}
},
methods : {
addTodoItem(){
if(this.newTodoItem !== ""){
this.$emit('addTodoItems', this.newTodoItem)
this.itemClear();
}else{
this.showModal = !this.showModal;
}
},
itemClear(){
this.newTodoItem = "";
},
closeModalBtn(){
this.showModal = !this.showModal;
}
},
components : {
modal
}
}
</script>
<style>
.closeModal{
padding-left : 98%;
}
</style>
3. List.vue
<template>
<div id="listApp">
<!-- fontawesome CDN-->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css"
/>
<!-- list 출력 -->
<div v-if="this.propsdata.length <= 0" class="ListIsEmpty"> 작성된 List가 없습니다. <br> List를 작성해주세요. </div>
<!-- 5. 기존에 todoItems를 propsdata로 바꿔줌 끝~!-->
<ul v-for="(todoItem, index) in propsdata" :key="todoItem.title" class="ShowTodoList">
<li><i class="fas fa-check" @click="toggleBtn(todoItem, index)" :class="{finishToo : todoItem.completed}"></i></li>
<li :class="{finish : todoItem.completed}">{{todoItem.title}}</li>
<li><i class="fas fa-trash-alt" @click="OneTodoItemDel(todoItem, index)" ></i></li>
<br>
</ul>
</div>
</template>
<script>
export default {
// 4. vue.js에서 propsdata 전달받음
props : ['propsdata'],
methods : {
OneTodoItemDel(todoItem, index){
this.$emit('removeOneItem', todoItem, index);
},
toggleBtn(todoItem){
todoItem.completed = !todoItem.completed;
localStorage.removeItem(todoItem.title);
localStorage.setItem(todoItem.title, JSON.stringify(todoItem));
}
}
}
</script>
<style>
.ShowTodoList{
margin : 0 auto;
padding : 2%;
text-align : left;
}
.ListIsEmpty{
font-size : 0.6rem;
line-height : 20px;
color : gray;
padding-top : 40px;
padding-bottom : 30px;
}
.finishToo{
color : gray;
}
.finish{
text-decoration: line-through;
color : gray;
}
.listApp{
width : 100%
}
.ShowTodoList {
width : 70%;
}
.ShowTodoList > li{
list-style: none;
float : left;
}
.ShowTodoList > li:nth-child(1){
width : 10%;
}
.ShowTodoList > li:nth-child(2){
width : 80%;
}
.ShowTodoList > li:nth-child(3){
width : 10%;
}
</style>
4. Footer.vue
<template>
<div>
<button @click="allRomove" class="todoAllRemove"> 전체 삭제 </button>
</div>
</template>
<script>
export default {
methods : {
allRomove(){
this.$emit('removeAllItems');
}
}
}
</script>
<style>
.todoAllRemove{
border : none;
border-radius : 10px;
padding : 6px;
font-size : 0.8rem;
}
</style>
*Header.vue는 코드 변화가 없어 첨부하지 않음
'SPA > Vue' 카테고리의 다른 글
vue.js todolist 만들기 [Helper함수 사용] --4 (0) | 2021.05.10 |
---|---|
vue.js Todolist 만들기 [vuex 리팩토링] --3 (0) | 2021.05.10 |
vue.js ToDoList 만들기 [컴포넌트 통신X] --1 (0) | 2021.05.07 |
[Vue.js] 인스턴스, 컴포넌트, 라우터, axios, 템플릿 문법, CLI (0) | 2021.05.06 |
Vuex - 프로젝트 구조화 및 모듈화 (0) | 2021.05.03 |