Develop/Vue

Vue 애플리케이션 구현 심화편

김니은  2020. 1. 26. 21:44
반응형

이전 글에서 삭제할 때 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

 

Modal Component — Vue.js

Vue.js - The Progressive JavaScript Framework

vuejs.org

 

해당 내용 수정본 모델 파일입니다.

 

<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인 경우 창은 뛰우는 형태입니다.

이렇게 뷰 모달을 이용하여 경고 창을 열 수 있습니다.

반응형