-Todolist 제작
header, input, list, footer 네 가지의 컴포넌트로 나누어 제작
-기능 설명
input : list 입력, list없을 시 작성 안내 문구, 입력칸이 공백인데 등록 버튼 클릭 시 작성 안내 모달창 출력
list : input으로 받은 list 출력, 할일 목록 진행중/완료 체크 기능, 일정 삭제 기능
footer : list 전체 삭제
-현재 문제점
1. list 입력 시 바로 적용되지 않고 새로 고침 후 화면에 일정이 등록됨
2. list 삭제 버튼 클릭 시 바로 적용이 안되고 새로 고침 후 삭제 확인 됨
2. list 전체 삭제 버튼 클릭 시 바로 적용되지 않고 새로 고침 후 삭제 확인 됨
=> 각 컴포넌트간에 데이터 전달이 안돼서 갱신이 안됨
-해결 방법
전체 컴포넌트에서 하나의 데이터만 바라보게 변경
1. App.vue
<template>
<div id="app">
<Header></Header>
<Input></Input>
<List></List>
<Footer></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 {
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>
2. Header.vue
<template>
<header>TO DO LIST!</header>
</template>
<script>
export default {
}
</script>
<style>
</style>
3. 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 !== ""){
const todoItem = {
title : this.newTodoItem,
completed : false
}
localStorage.setItem(todoItem.title, JSON.stringify(todoItem));
this.itemClear();
}else{
this.showModal = !this.showModal;
}
},
itemClear(){
this.newTodoItem = "";
},
closeModalBtn(){
this.showModal = !this.showModal;
}
},
components : {
modal
}
}
</script>
<style>
.closeModal{
padding-left : 98%;
}
</style>
4. Modal.vue
<template>
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<!--모달헤더-->
<div class="modal-header">
<slot name="header">
</slot>
</div>
<!-- 모달바디 -->
<div class="modal-body">
<slot name="body">
</slot>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
}
</script>
<style>
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: table;
transition: opacity 0.3s ease;
}
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
.modal-container {
width: 300px;
margin: 0px auto;
padding: 20px 30px;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
transition: all 0.3s ease;
font-family: Helvetica, Arial, sans-serif;
}
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
.modal-body {
margin: 20px 0;
padding-bottom : 5%;
}
.modal-default-button {
float: right;
}
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
.modal-enter .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
</style>
5. 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="todoItems.length <= 0" class="ListIsEmpty"> 작성된 List가 없습니다. <br> List를 작성해주세요. </div>
<ul v-for="(todoItem, index) in todoItems" :key="todoItem" 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)" ></i></li>
<br>
</ul>
</div>
</template>
<script>
export default {
data(){
return {
todoItems : []
}
},
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 : {
OneTodoItemDel(todoItem, index){
localStorage.removeItem(todoItem.title);
this.todoItems.splice(index, 1);
},
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>
6. Footer.vue
<template>
<div>
<button @click="allRomove" class="todoAllRemove"> 전체 삭제 </button>
</div>
</template>
<script>
export default {
methods : {
allRomove(){
localStorage.clear();
}
}
}
</script>
<style>
.todoAllRemove{
border : none;
border-radius : 10px;
padding : 6px;
font-size : 0.8rem;
}
</style>
'SPA > Vue' 카테고리의 다른 글
vue.js Todolist 만들기 [vuex 리팩토링] --3 (0) | 2021.05.10 |
---|---|
vue.js Todolist 만들기 [컴포넌트 통신O] --2 (0) | 2021.05.07 |
[Vue.js] 인스턴스, 컴포넌트, 라우터, axios, 템플릿 문법, CLI (0) | 2021.05.06 |
Vuex - 프로젝트 구조화 및 모듈화 (0) | 2021.05.03 |
Vuex - 헬퍼 함수 (0) | 2021.05.03 |