voter-taker 컴포넌트 생성
root 컴포넌트와 voter 컴포넌트 사이에 voter-taker 컴포넌트를 하나 추가한다.
부모 템플릿은 아래와 같다.
1 2 3 |
<div id="app"> <voter-taker></voter-taker> </div> |
전체 스크립트는 아래와 같다. 전과 동일하게 작동하는지 테스트해보자.
root -> voter-taker -> voter
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 41 42 43 44 45 46 47 48 49 50 51 |
Vue.component('voter-taker', { template: `<div> <voter v-bind:name="name" :result="result" v-on:on-agree="handleAgree" v-on:on-disagree="handleDisagree"></voter> </div>`, data: function() { return { name: 'hong kil dong', result: null } }, methods: { handleAgree: function(){ this.result = 'agree'; }, handleDisagree: function () { this.result = 'disagree'; } } }); Vue.component('voter', { template: `<div> <h2>{{name}}: {{ result }}</h2> <button @click="agree">Agree</button> <button @click="disagree">DisAgree</button> </div>`, props: ['name', 'result'], data: function() { return { } }, methods: { agree: function(){ this.$emit('on-agree'); }, disagree: function () { this.$emit('on-disagree'); } } }); var app = new Vue({ el: '#app', data: { }, methods: { } }); |
voter 컴포넌트 확장
이제 voter 컴포넌트를 2개 더 생성해서 3개를 만들자.
voter-taker가 가지고있는 데이터는 다음과 같다.
1 2 3 4 5 6 7 8 9 |
data: function() { return { voters: [ {name: 'hong kil dong', result: null}, {name: 'lee dong kee', result: null}, {name: 'kim chul su', result: null}, ] } }, |
voter-taker 가 가지는 이 데이터를 voter 자식 컴포넌트에게 어떻게 넘겨줘야 할까?
v-for 구문을 사용하여 반복하고 객체로 데이터를 넘긴다.
1 2 3 4 5 |
template: `<div> <voter v-for="item in voters" v-bind:name="item.name" :result="item.result" v-on:on-agree="handleAgree" v-on:on-disagree="handleDisagree"></voter> </div>`, |
그러나 콘솔창에 리스트를 유니크하게 구분할 키 값이 없다고 아래와 같은 waringin이 발생한다.
vue.js:603 [Vue tip]: <voter v-for=”item in voters”>: component lists rendered with v-for should have explicit keys. See https://vuejs.org/guide/list.html#key for more info.
found in
—> <VoterTaker>
<Root>
1 2 3 4 5 |
template: `<div> <voter v-for="(item, index) in voters" v-bind:name="item.name" :result="item.result" v-on:on-agree="handleAgree" v-on:on-disagree="handleDisagree" :key="index"></voter> </div>`, |
key에 index 값을 할당해준다.
객체를 bind할때는 아래와 같이 이름을 생략하고 한번에 바인딩할수 있다. v-bind=”item”
1 2 3 4 5 |
template: `<div> <voter v-for="(item, index) in voters" v-bind="item" v-on:on-agree="handleAgree" v-on:on-disagree="handleDisagree" :key="index"></voter> </div>`, |
agree, disagree 버튼을 누르면 voter-taker 에게 전달하여 찬성 반대 숫자를 집계해서 보여주도록 하자.
voter에서 agree, disagree 버튼을 누르면 해당 데이터를 객체로 해서 이벤트로 emit 해서 넘긴다.
1 2 3 4 5 6 7 8 |
methods: { agree: function(){ this.$emit('on-agree', {name: this.name, result: 'agree'}); }, disagree: function () { this.$emit('on-disagree', {name: this.name, result: 'disagree'}); } } |
voter-taker에서는 객체의 이름에 매피하는 result 값을 업데이트 한뒤에 전체 찬성과 반대 를 집계한다.
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 41 42 43 44 45 46 |
Vue.component('voter-taker', { template: `<div> <p>Agree: {{totalAgree}}</p> <p>Disagree: {{totalDisagree}}</p> <voter v-for="(item, index) in voters" v-bind="item" v-on:on-agree="handleAgree" v-on:on-disagree="handleDisagree" :key="index"></voter> </div>`, data: function() { return { voters: [ {name: 'hong kil dong', result: null}, {name: 'lee dong kee', result: null}, {name: 'kim chul su', result: null}, ], totalAgree: 0, totalDisagree: 0 } }, methods: { handleAgree: function(voter){ console.log(voter); // 해당 name을 찾아서 result 값 업데이트 this.voters.forEach(item => { if (item.name === voter.name) { item.result = voter.result; } }); // 전체 찬성, 반대 숫자 카운트 this.totalAgree = 0; this.totalDisagree = 0; this.voters.forEach(item => { if (item.result === 'agree') { ++this.totalAgree; } else if (item.result === 'disagree') { ++this.totalDisagree; } }) }, handleDisagree: function (voter) { console.log(voter); this.handleAgree(voter); } } }); |