✔️사용 이유
로그 목록 조회 / 스케줄 목록 조회 총 2 화면에서 페이징 기능을 구현해야 했는데, 각 화면에서 페이징을 구현하기보다 페이징을 컴포넌트화해서 재사용하고자 함.
자식 컴포넌트에게 props라는 특별한 속성으로, 데이터를 전달할 수 있다.
자식 컴포넌트에게 이벤트를 받아와 동작할 내용을 구현한다.
v-on: 자식에서 받아온 이벤트 이름 = "자식에서 받아온 이벤트를 사용할 함수"
v-bind: 자식으로 보낼 props 이름 = "부모에서 사용하는 데이터 이름"
부모 컴포넌트에게 이벤트를 전달(이벤트 트리거)할 수 있다.
→ 이벤트 + 매개변수 값이 전달 가능하다!!
props: [ "상위에서 받은 props 이름" ]
this.$emit("상위로 보낼 이벤트 이름")
this.$emit("상위로 보낼 이벤트 이름", 매개변수)
// 부모 컴포넌트
<template>
<div>
// v-on:자식에서 받아온 이벤트 이름 = "자식에서 받아온 이벤트를 사용할 함수"
// v-bind:자식으로 보낼 props 이름 = "부모에서 사용하는 데이터 이름"
// 띄어쓰기 하면 인식 못함!!
<ChildComponent
v-on:childEvent="updateParentValue"
v-bind:childValue="parentValue"/>
</div>
</template>
<script>
import ChildComponent from "@/components/childComponent.vue";
export default {
name: "ParentComponent",
components: { ChildComponent },
data(){
return {
parentValue: 1,
};
},
methods: {
updateParentValue() {
this.parentVaule++;
console.log(this.parentVaule)
// 2, 3, 4, ... 누를 때마다 증가하는 것 확인 가능
},
},
};
</script>
// 자식 컴포넌트
<template>
<div>
{{ this.childValue }}: 부모로부터 넘어온 데이터 값
</div>
<button @click="updateParentValue">부모의 데이터 값 증가</button>
</template>
<script>
export default {
name: "ChildComponent",
// props: [ "상위에서 받은 props 이름" ]
props: ['childValue'],
methods: {
updateParentValue() {
// this.$emit("상위로 보낼 이벤트 이름")
this.$emit("childEvent");
},
},
};
</script>
나는 백엔드에서 목록 조회를 하면, 아래 사진과 같이 페이지 정보가 함께 넘어왔다.
이렇게 되는 거지요 유남생?
// Pagination.vue (자식 컴포넌트)
<template>
<div class="mt-5">
<div class="flex justify-center px-4 py-4 overflow-x-auto rounded-md">
<div class="flex mr-4 rounded">
<button
@click="firstPage()"
class="px-3 py-2 ml-0 leading-tight bg-white text-indigo-700 border border-r-0 border-gray-200 rounded-l hover:bg-indigo-500 hover:text-white">
처음으로
</button>
<button
@click="prevPage()"
class="px-3 py-2 leading-tight bg-white text-indigo-700 border border-r-0 border-gray-200 hover:bg-indigo-500 hover:text-white">
이전
</button>
// 페이지 세팅을 for문으로 돌리고, 현재 페이지 색상 변경, 클릭 시 페이지 이동
<button
v-for="page in setPages" :key="page"
:class="[page === this.paging.nowPage ? 'selected' : '']"
class="px-3 py-2 leading-tight bg-white text-indigo-700 border border-r-0 border-gray-200 hover:bg-indigo-500 hover:text-white"
@click="changeNowPage(page)">
{{ page }}
</button>
<button
@click="nextPage()"
class="px-3 py-2 leading-tight bg-white text-indigo-700 border border-r-0 border-gray-200 hover:bg-indigo-500 hover:text-white">
다음
</button>
<button
@click="lastPage()"
class="px-3 py-2 leading-tight bg-white text-indigo-700 border border-gray-200 rounded-r hover:bg-indigo-500 hover:text-white">
끝으로
</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Pagination',
// 부모 컴포넌트에서 받아오는 props 데이터
props:['paging'],
computed: {
// 화면에 표시할 페이지 숫자 배열
setPages() {
let pages = [];
for(let num = this.paging.startPage; num <= this.paging.endPage; num++){
pages.push(num);
}
return pages;
},
},
// 부모 컴포넌트로 이벤트 전달
methods:{
prevPage(){
this.$emit("prevPage");
},
nextPage(){
this.$emit("nextPage");
},
firstPage(){
this.$emit("firstPage");
},
lastPage(){
this.$emit("lastPage");
},
// 숫자를 눌렀을 때 작동하는 페이지 이동
// 이벤트 + 매개변수(page) 전달!
changeNowPage(page){
this.$emit("changeNowPage", page);
}
},
};
</script>
<style>
button.selected{
background-color: #4338CA;
color: white;
}
</style>
// ScheduleLog.vue (부모 컴포넌트)
<template>
// ... (생략)
<div>
//(v-bind): 로 props를 자식 컴포넌트로 보내기
//v-on: 으로 자식 컴포넌트로부터 이벤트 받기
<Pagination
:paging="paging"
v-on:prevPage="prevPage"
v-on:nextPage="nextPage"
v-on:firstPage="firstPage"
v-on:lastPage="lastPage"
v-on:changeNowPage="changeNowPage"/>
</div>
</template>
<script>
import Pagination from '@/components/common/Pagination.vue';
export default {
name: 'ScheduleLog',
components: {
Pagination,
},
data () {
return {
logs: [],
paging: {},
}
},
mounted() {
//mount 될 때 log list 불러오기
this.getJobLog();
},
methods:{
// ...(생략)
// 페이징
prevPage(){
if(this.paging.nowPage > 1){
this.paging.nowPage -= 1;
this.getJobLog(this.paging.nowPage);
}else if(this.paging.nowPage == 1){
alert('첫번째 페이지입니다.');
}
},
nextPage(){
if(this.paging.lastPage > this.paging.nowPage){
this.paging.nowPage += 1;
this.getJobLog(this.paging.nowPage);
}else if(this.paging.lastPage == this.paging.nowPage){
alert('마지막 페이지입니다.');
}
},
firstPage(){
if(this.paging.nowPage != 1){
this.paging.nowPage = 1;
this.getJobLog(this.paging.nowPage);
}else if(this.paging.nowPage == 1){
alert('첫번째 페이지입니다.');
}
},
lastPage(){
if(this.paging.nowPage != this.paging.lastPage){
this.paging.nowPage = this.paging.lastPage;
this.getJobLog(this.paging.nowPage);
}else if(this.paging.lastPage == this.paging.nowPage){
alert('마지막 페이지입니다.');
}
},
// 자식 컴포넌트로부터 받아온 매개 변수(page) 사용하기
changeNowPage(page){
if(page !== this.paging.nowPage){
this.paging.nowPage = page;
this.getJobLog(this.paging.nowPage);
}
}
},
}
</script>