Q&A 게시판 구현하기 - Part 2 게시글 상세보기 및 페이징 처리

Project Diary/Vue (Roblox WebSite)

Q&A 게시판 구현의 두 번째 파트로, 게시글 상세보기와 페이징 처리 방법 기록


1. 게시글 상세보기 컴포넌트 (BoardDetail.vue)

게시글의 상세 내용을 표시하는 BoardDetail.vue 컴포넌트를 구현합니다.

 

<template>
  <div class="board__detail" :class="{ dark: changeDarkMode }">
    <div class="detail__title">
      <h2>Q&amp;A</h2>
    </div>
    <div class="go__to__list">
      <router-link to="/qna" :class="{ dark: changeDarkMode }">{{
        $t("[3].boarddetail.list")
      }}</router-link>
    </div>
    <table border="1">
      <colgroup>
        <col />
        <col />
      </colgroup>
      <tbody>
        <tr>
          <td colspan="2">
            {{ $t("[3].boarddetail.title") }} {{ item.subject }}
          </td>
          <td colspan="1" v-if="!answerList">
            {{ $t("[3].boarddetail.waiting") }}
          </td>
          <td colspan="1" v-else>{{ $t("[3].boarddetail.completed") }}</td>
        </tr>
        <tr>
          <td>{{ $t("[3].boarddetail.writer") }}: {{ item.writer }}</td>
          <td>{{ $t("[3].boarddetail.date") }}: {{ item.date }}</td>
          <td>{{ $t("[3].boarddetail.hit") }}: {{ item.hit }}</td>
        </tr>
        <tr>
          <td colspan="3" class="content">
            <pre>{{ item.content }}</pre>
          </td>
        </tr>
      </tbody>
    </table>

    <table
      v-if="answerList"
      class="answer__list"
      :class="{ dark: changeDarkMode }"
    >
      <tbody>
        <tr>
          <td class="answer__top">
            <p>{{ $t("[3].boarddetail.answer") }}</p>
            <p>{{ $t("[3].boarddetail.date") }}: {{ answerList?.date }}</p>
          </td>
        </tr>
        <tr>
          <td>
            <pre>{{ answerList?.answer }}</pre>
          </td>
        </tr>
      </tbody>
    </table>
    <form
      @submit.prevent="answerPost"
      v-if="show && !answerList"
      class="answer__post"
    >
      <p>'{{ item.subject }}'{{ $t("[3].boarddetail.reply") }}</p>
      <textarea v-model="answer"></textarea>
      <div class="answer__btn">
        <button type="submit">{{ $t("[3].boarddetail.post") }}</button>
      </div>
    </form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      item: null,
      managerDate: "",
      answer: "",
      answerList: null,
      managerEamil: "",
    };
  },
  created() {
    this.$store.commit("hit__Update", this.$route.params.id);
    this.item = this.$store.getters.fnGetBoardList.find(
      (item) => item.id === this.$route.params.id
    );
    this.answerList = this.$store.getters.fnGetAnswerList.find(
      (item) => item.id === this.$route.params.id
    );
    this.managerEamil = this.$store.getters.fnGetLogined.email;
  },
  computed: {
    show() {
      if (this.managerEamil === "manager@gmail.com") {
        return true;
      } else {
        return false;
      }
    },
    changeDarkMode() {
      return this.$store.getters.fnGetDark;
    },
  },
  methods: {
    answerPost() {
      this.$store.commit("on__answer", {
        answer: this.answer,
        id: this.$route.params.id,
      });
      this.answerList = this.$store.getters.fnGetAnswerList.find(
        (item) => item.id === this.$route.params.id
      );
      console.log(this.answerList);
    },
  },
};
</script>

 

  • 1. 게시글 상세보기: created 훅에서 Vuex를 통해 현재 게시글의 상세 정보를 가져옵니다.
  • 2. 답변 작성: 관리자가 로그인했을 경우, 답변 작성 폼을 표시하고, 작성된 답변을 Vuex에 저장합니다.

 

2. Q&A 목록 페이지 및 페이징 처리 (QnAList.vue)

Q&A 목록 페이지와 페이징 처리를 구현합니다.

 

<template>
  <div class="qna__list">
    <board-list :qnaData="qnaData" :currentPage="currentPage" />
    <pagination
      :totalItems="this.$store.getters.fnGetBoardList.length"
      :currentPage.sync="currentPage"
      :itemPerPage="itemPerPage"
    />
  </div>
</template>

<script>
import BoardList from "@/components/board/BoardList.vue";
import Pagination from "@/components/layout/Pagination.vue";
export default {
  data() {
    return {
      totalItems: [],
      currentPage: 1,
      itemPerPage: 10,
      qnaData: [],
    };
  },
  components: { BoardList, Pagination },
  created() {
    this.totalItems = JSON.parse(
      JSON.stringify(this.$store.getters.fnGetBoardList)
    );
    for (
      let i = 0;
      i <
      Math.ceil(this.$store.getters.fnGetBoardList.length / this.itemPerPage);
      i++
    ) {
      this.qnaData.push(this.totalItems.splice(0, 10));
    }
    console.log(this.qnaData);
    console.log(this.$store.getters.fnGetBoardList);
  },
};
</script>

<style lang="scss" scoped>
.qna__list {
  max-width: 1000px;
  margin: 0 auto;
}
</style>

 

  • 1.페이징 처리: created 훅에서 전체 게시글을 페이지별로 나누어 qnaData 배열에 저장합니다.
  • 2.페이지네이션 컴포넌트: pagination 컴포넌트를 사용하여 현재 페이지와 총 아이템 수를 전달합니다.
  • 3.현재 페이지 상태 관리: currentPage 속성을 사용하여 현재 페이지 상태를 관리하고, 페이지가 변경될 때마다 목록을 업데이트합니다.

 

3. Vuex 설정 업데이트 (store/index.js 및 store/board/index.js)

페이징 처리를 위해 Vuex 설정을 업데이트합니다.

 

store/board/index.js

import dayjs from "dayjs";

export default {
  state: {
    boardList: [], // 게시글 목록 데이터
    answerList: [], // 답변 목록 데이터
  },
  mutations: {
    on__Insert(state, payload) {
      let { writer, date, subject, content, status } = payload;
      let id = state.boardList.length ? state.boardList[0].id + 1 : 1;
      state.boardList.unshift({
        id,
        subject,
        writer,
        content,
        date,
        hit: 0,
        status,
      });
    },
    on__answer(state, payload) {
      let date = dayjs().format("YYYY-MM-DD");
      state.answerList.push({ answer: payload.answer, id: payload.id, date });
      state.boardList.find((item) => item.id === payload.id).status = true;
    },
    hit__Update(state, payload) {
      state.boardList.find((item) => item.id == payload).hit++;
    },
  },
  getters: {
    fnGetBoardList: (state) => state.boardList,
    fnGetAnswerList: (state) => state.answerList,
  },
};

 

  • 1.상태 관리: state 객체에서 boardList와 answerList를 관리합니다.
  • 2.변이 함수: on__Insert, on__answer, hit__Update 변이 함수를 통해 상태를 변경합니다.
  • 3.게터: fnGetBoardList, fnGetAnswerList 게터를 통해 상태를 접근합니다.

 

 

 

01
< 일반 유저 Q&A상세페이지 관리자 >

 

01
< 답변 전 Q&A상세페이지 답변 후 >