이전 글에서 삭제할 때 List.vue와 Footer.vue가 연결되지 않아 삭제할 때 List Data가 삭제되지 않았습니다.
같은 데이터 속성을 사용하기 위해 최상위 컴포넌트인 App 컴포넌트에 Data를 정의하고, 하위 컴포넌트에 props로 전달하면 됩니다.
props와 이벤트 전달
최상위 컴포넌트에 이전 글에 선언했던 Data를 구성해야합니다.
<template>
<div id="app">
<Header></Header>
<Inputcheck v-on:addItem="addItem"></Inputcheck>
<List v-bind:propsdata="ItemLists"></List>
<Footer></Footer>
</div>
</template>
...
export default {
data() {
return {
ItemLists: []
}
}
...
}
App.vue에 data() 속성을 선언 후, 이전 List.vue에는 props로 전달해야 합니다.
List 컴포넌트의 propsdata 속성에 props로 전달하였습니다.
export default {
props: ['propsdata'],
}
이제 추가 기능을 다시 구현합시다.
Input 컴포넌트의 addItem() 메서드에 this.$emit()를 이용하여 값을 전달합니다.
그 후 로컬 스토리지에 데이터를 저장하는 localStorage.setItem() 를 제거합니다.
addItem() {
if (this.newItem !== "") {
var value = this.newItem && this.newItem.trim();
this.$emit('addItem', value)
this.clearInput();
}
},
이제 App 컴포넌트의 addItem() 메서드를 수정합니다.
addItem(ItemList) {
localStorage.setItem(ItemList, ItemList);
this.ItemLists.push(ItemList);
},
이렇게 변경을 하게 되면 Input 컴포넌트에서 App 컴포넌트로 신호를 보내 App 컴포넌트의 addItem 메서드를 실행합니다.
addItem 메서드의 인자값 ItemList는 Input 컴포넌트에서 올려 보낸 텍스트 값입니다.
이 값을 로컬 스토리지에 저장하고, App 컴포넌트의 ItemList 데이터 속성에 추가합니다.
이제 List 컴포넌트도 수정해야 합니다.
<li v-for="(ItemList, index) in propsdata" v-bind:key="ItemList" class="shadow">
<i class="checkBtn fa fa-check" aria-hidden="true"></i>
{{ ItemList }}
<span class="removeBtn" type="button" @click="removeItem(ItemList, index)">
<i class="fa fa-trash-o" aria-hidden="true"></i>
</span>
</li>
For문 내의 ItemList와 Index를 propsdata 디렉티브 대상으로 변경해야 합니다.
이제 제거기능도 개선시켜봅시다.
<Footer v-on:removeAll="clearAll"></Footer>
App.vue 파일 모두 제거였던 Footer를 수정합니다.
methods: {
clearAll() {
localStorage.clear();
this.ItemLists = [];
},
}
methods에는 Footer.vue에 있던 내용을 추가합니다.
하위 컴포넌트인 Footer.vue를 수정해봅시다.
<script>
export default {
methods: {
clearData() {
this.$emit('removeAll');
}
}
}
</script>
모두 제거 버튼을 클릭하면 해당 이벤트를 상위 컴포넌트인 App.vue로 전달합니다.
그럼 개별 제거를 구현합니다.
<template>
...
<List v-bind:propsdata="ItemLists" @removeItem="removeItem"></List>
...
</template>
...
methods: {
removeItem(ItemList, index) {
localStorage.removeItem(ItemList);
this.ItemLists.splice(index, 1);
}
}
위는 App.vue의 수정본입니다.
methods: {
removeItem(ItemList, index) {
this.$emit('removeItem', ItemList, index);
}
},
위는 List 수정본입니다.
List.vue의 @removeItem는 앞에서 다뤘던 이벤트 전달 디렉티브인 v-on:removeItem의 약식 문법입니다.
제거 아이콘을 클릭 시, List 컴포넌트의 removeItem() 메서드에서 이벤트를 발생시켜 App 컴포넌트로 전달합니다.
컴포넌트가 분리되어 데이터를 공유하지 못한 문제점을 컴포넌트 통신 방법으로 해결할 수 있습니다.
그 외의 다른 기능 추가
Vue Animation
뷰 애니메이션은 뷰 프레임워크 다체에서 지원하는 애니메이션 기능입니다.
데이터 추가와 삭제, 변경에 대한 페이드 인, 페이드 아웃 등 여러 효과를 지원해줍니다.
간단하게 데이터를 추가, 삭제할 때 매끄럽게 동작하도록 제작해봅시다.
<transition-group name="list" tag="ul">
<li v-for="(ItemList, index) in propsdata" v-bind:key="ItemList" class="shadow">
<i class="checkBtn fa fa-check" aria-hidden="true"></i>
{{ ItemList }}
<span class="removeBtn" type="button" @click="removeItem(ItemList, index)">
<i class="fa fa-trash-o" aria-hidden="true"></i>
</span>
</li>
</transition-group>
기존에 있던 ul 태그를 제거 후, transition-group 태그로 변경합니다.
해당 태그는 목록에 애니메이션을 추가할 때 사용하는 태그이며, tag 속성에 애니메이션이 들어갈 Html 태그 이름을 지정하면 됩니다.
<style>
.list-item {
display: inline-block;
margin-right: 10px;
}
.list-move {
transition: transform 1s;
}
.list-enter-active, .list-leave-active {
transition: all 1s;
}
.list-enter, .list-leave-to {
opacity: 0;
transform: translateY(30px);
}
...
</style>
transition-group 태그에 적용할 css 속성을 추가하겠습니다.
move, enter-active, leave-active, enter, leave-to는 데이터가 들엉오고 나가는 동작을 정의하는 css 입니다.
Data를 추가하거나 삭제할 때 애니메이션 동작하는 모습을 볼 수 있습니다.
Vue Modal
현재 Input에 값을 넣지 않고 추가를 하면 아무 반응이 없습니다.
자바스크립트의 기본 경고 창을 활용해 예외 처리를 할 수 있지만 Vue 공식 팝업 대화상자인 모달을 활용하여 할 수 있습니다.
팝업 모델 관련 소스는 아래 사이트 기반으로 제작하였습니다.
https://vuejs.org/v2/examples/modal.html
해당 내용 수정본 모델 파일입니다.
<template lang="html">
<transition name="modal">
<div class="modal-mask" @keyup.esc="$emit('close')">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
</slot>
</div>
</div>
</div>
</div>
</transition>
</template>
<style lang="css">
.closeModalBtn {
color: #62acde;
}
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
display: table;
transition: opacity .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, .33);
transition: all .3s ease;
font-family: Helvetica, Arial, sans-serif;
}
.modal-header h3 {
margin-top: 0;
color: #62acde;
}
.modal-body {
margin: 20px 0;
}
.modal-default-button {
float: right;
}
.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>
저는 기존에 있던 components 폴더 위에 common 이라는 폴더를 생성 후 modal.vue 파일을 제작하였습니다.
이제 modal.vue 파일을 연결시켜 보겠습니다.
Input.vue 파일을 수정해보겠습니다.
<template>
...
<modal v-if="showModal" @close="showModal = false">
<h3 slot="header">Warninng</h3>
<span slot="footer" @click="showModal = false">
Empty Data!
<i class="closeModalBtn fa fa-times" aria-hidden="true"></i>
</span>
</modal>
</div>
</template>
<script>
import Modal from './common/Modal.vue' // import
export default {
components: { Modal: Modal },
data() {
return {
newItem: '',
showModal: false // 추가
}
},
methods: {
addItem() {
if (this.newItem !== "") {
var value = this.newItem && this.newItem.trim();
this.$emit('addItem', value)
this.clearInput();
}else {
this.showModal = !this.showModal; //값을 입력 안할 때
}
...
</script>
modal.vue 파일을 import하여야 이용하실 수 있습니다.
값을 false 시킨 후, 값 없이 추가할 때 false인 경우 창은 뛰우는 형태입니다.
이렇게 뷰 모달을 이용하여 경고 창을 열 수 있습니다.
'Develop > Vue' 카테고리의 다른 글
[Nuxt.js & Node.js] S3에 다중 이미지 업로드를 해보자 (0) | 2020.04.05 |
---|---|
[Nuxt.js] 설명 및 Nginx / PM2 연동 (0) | 2020.04.05 |
Vue 애플리케이션 만들기 (0) | 2020.01.26 |
Vue 프로젝트 구성 (0) | 2020.01.26 |
Vue 템플릿 (0) | 2020.01.26 |