Vue 페이지 구현(+props 전달)

맘비·2023년 1월 3일
0

Front-end

목록 보기
2/9

✔️사용 이유
로그 목록 조회 / 스케줄 목록 조회 총 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>

내 상황에 적용한 예시

나는 백엔드에서 목록 조회를 하면, 아래 사진과 같이 페이지 정보가 함께 넘어왔다.

  • nowPage: 현재 페이지
  • total: 총 목록 아이템 개수
  • startPage: (현재 페이지 기준으로 보여지는) 첫 번째 숫자
  • endPage:(현재 페이지 기준으로 보여지는) 마지막 숫자
  • lastPage: 전체 페이지 중 마지막 페이지
  • start & end: 한 페이지 당 보여지는 목록 아이템 (총 10개)

이렇게 되는 거지요 유남생?

// 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>
profile
기록만이 살 길 ... 말하는 감자애오

0개의 댓글