하위 컴포넌트에서 상위 컴포넌트 관계 맺기 대기자 신청 양식을 작성하는 WaitingForm
컴포넌트, 그리고 데이터를 받아서 리스트에 추가하는 WaitingList
컴포넌트가 있다.
WaitingForm
을 하위 컴포넌트로 WaitingList
를 상위 컴포넌트로 관계를 맺어주고 하위 컴포넌트에서 상위 컴포넌트로 데이터를 넘기는 작업 을 해보자.
1. 컴포넌트 간의 관계 맺어주기
export와 import로 컴포넌트 간에 부모, 자식 관계를 만들어줄 수 있다. 이때 부모(상위) 컴포넌트는 하위 컴포넌트를 import하는 쪽이다.
2. WaitingForm.vue : 하위 컴포넌트
1 2 3 4 5 6 <script> export default { name:"WaitingForm" , } </script>
3. WaitingList.vue : 상위 컴포넌트
1 2 3 4 5 6 7 8 <script> import WaitingForm from "./WaitingForm" ;export default { name:"WaitingList" , } </script>
데이터 전달
1. 하위 컴포넌트 : WaitingForm의 template
#1 : v-model로 컴포넌트 data의 input_name
과 엘리먼트를 연결 시킨다. submit을 통해 form이 제출되면 input 태그에 있던 값이 컴포넌트 데이터에 전달된다.
#2 : select 태그에서는 option이 아닌 select태그에 v-model을 쓴다 .
#3 : placeholder 역할을 하는 옵션 태그이다.
#4 : v-for
를 통해 1부터 10까지 반복되며 그 값은 number에 담긴다. v-bind:value="number"
속성을 통해 템플릿 내에서 콧수염 태그로 변수를 사용할 수 있다. ex) \{\{number\}\}명
. \
백슬래시는 빼고 생각하면 된다.
#5 : 클릭하면 컴포넌트 내의 prevent_event
메서드를 호출한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <template > ... 생략 ... <form > <h3 > 대기자 등록</h3 > <div > <label for ="inputName" > 이름</label > <input v-model ="input_name" placeholder ="이름을 입력해주세요." type ="name" > </div > <div > <select v-model ="input_people_numbers" id ="inputPeople" > <option value ="" disabled selected > 0명</option > <option v-for ="number in 10" v-bind:value ="number" :key ="number.id" selected ="0" > \{\{number\}\}명 </option > </select > </div > <button @click ="prevent_event" type ="submit" > 등록 </button > </form > </template >
2. 하위 컴포넌트 : WaitingForm의 script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <script> export default { name:"WaitingForm" , data: () => { return { is_show: false , input_name:'' , input_people_numbers:'' , }; }, methods: { form_toggle: function ( ) { this .is_show = !this .is_show; }, prevent_event: function (event ) { if (event) event.preventDefault(); this .create_waiting(); }, initialize_data: function ( ) { this .input_name = '이름을 입력해주세요.' ; this .input_people_numbers = '0' ; }, create_waiting: function ( ) { let wait = { 'name' : this .input_name, 'people' : this .input_people_numbers, } this .initialize_data(); this .form_toggle(); this .$emit('create_wait' , wait); }, } } </script>
3. 이벤트 버스, emit
하위 컴포넌트에서 자식 컴포넌트로 이벤트와 함께 데이터를 전달할 때 emit을 사용한다. this.$emit('이벤트명', 데이터1, 데이터2, ...)
와 같이 쓴다.
1 this .$emit('create_wait' , wait);
4. 상위 컴포넌트 : WaitingList의 template
#5 : <WaitingForm @create_wait="update_waiting"/>
으로 create_wait
이벤트가 발생하면 상위 컴포넌트 내 메서드 update_waiting
을 호출한다.
#4 : 하위 컴포넌트를 전달할 때 라우터 뷰를 사용한다. 템플릿 내에서는 오직 하나의 컴포넌트만 존재해야 하므로, 하위 컴포넌트를 <div id="WaitingList"></div>
안에 써야 한다.
#1 : update_waitings라는 배열에 담긴 객체를 하나씩 꺼내 item
에 담는다. index에는 배열이 갖는 인덱스 숫자가 담긴다.
#2 : #1에서 item을 v-bind:value="item"
으로 바인딩했기 때문에 템플릿 내에서 콧수염 태그로 데이터를 사용할 수 있다.
#3 : delete_waiting 메서드를 호출해 대기자 리스트에서 해당 대기자를 삭제한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <template > <div id ="WaitingList" > <div > <ul v-for ="(item, index) in updated_waitings" v-bind:value ="item" :key ="item.id" > <li > 이름 : \{\{ item.name\}\}</li > <li > 예약 번호 : \{\{ index + 1\}\}</li > <li > 예약 인원 : \{\{ item.people\}\}명</li > <button @click ="delete_waiting" type ="button" class ="close" aria-label ="Close" > <span aria-hidden ="true" > ×</span > </button > </ul > </div > <router-view > <WaitingForm @create_wait ="update_waiting" /> </router-view > </div > </template >
5. 상위 컴포넌트 : WaitingList의 script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <script> import WaitingForm from "./WaitingForm" ;export default { name: "WaitingList" , components:{ WaitingForm }, data: () => { return { updated_waitings: [], } }, methods: { update_waiting: function (waiting_list ) { this .updated_waitings.push(waiting_list); }, delete_waiting: function ( ) { this .updated_waitings.pop(); } }, } </script>
6. 결과