Q&A 게시판 구현하기 - Part 1 게시글 작성 및 목록 표시

Project Diary/Vue (Roblox WebSite)

 Q&A 게시판을 구현하는 방법 기록


Vue.js와 Vuex를 사용하여 게시판을 구성하고, 데이터 상태를 관리하는 방법을 살펴보겠습니다. 이번 파트에서는 게시글 작성과 목록 표시를 구현합니다.

 

1. 게시글 작성 컴포넌트 (BoardWrite.vue)

먼저, 사용자가 게시글을 작성할 수 있는 BoardWrite.vue 컴포넌트를 구현합니다.

<template>
  <div class="boardWrite" :class="{ dark: changeDarkMode }">
    <div class="write__title">
      <h2>
        <i class="fa-regular fa-pen-to-square"></i>&nbsp;{{
          $t("[3].boarddetail.ask")
        }}
      </h2>
    </div>
    <form @submit.prevent="onSubmit">
      <table border="1">
        <colgroup>
          <col />
          <col />
        </colgroup>
        <tbody>
          <tr>
            <td>{{ $t("[3].boarddetail.writer") }}</td>
            <td>
              <input
                type="text"
                v-model="writer"
                disabled
                :class="{ dark: changeDarkMode }"
              />
            </td>
            <td>
              <input
                type="text"
                v-model="date"
                disabled
                :class="{ dark: changeDarkMode }"
              />
            </td>
          </tr>
          <tr>
            <td>{{ $t("[3].boarddetail.title") }}</td>

            <td colspan="2">
              <input
                type="text"
                v-model="subject"
                maxlength="55"
                :class="{ dark: changeDarkMode }"
              />
            </td>
          </tr>
          <tr>
            <td>{{ $t("[3].boarddetail.content") }}</td>
            <td colspan="2">
              <textarea
                v-model="content"
                :class="{ dark: changeDarkMode }"
              ></textarea>
            </td>
          </tr>
        </tbody>
      </table>
      <div class="btn">
        <button type="submit">{{ $t("[3].boarddetail.writingout") }}</button>
        <router-link to="/qna">{{ $t("[3].boarddetail.list") }}</router-link>
      </div>
    </form>
  </div>
</template>

<script>
import dayjs from "dayjs";
export default {
  data() {
    return {
      writer: "",
      date: "",
      subject: "",
      content: "",
    };
  },
  methods: {
    onSubmit() {
      // 게시글 작성 데이터를 Vuex 저장소에 커밋
      this.$store.commit("on__Insert", {
        writer: this.writer,
        subject: this.subject,
        content: this.content,
        date: this.date,
        status: false,
      });
      this.$router.push("/qna"); // 작성 후 Q&A 목록 페이지로 이동
    },
  },
  created() {
    // 작성자 이름과 작성 날짜를 초기화
    this.writer = this.$store.getters.fnGetLogined.name;
    this.date = dayjs().format("YYYY-MM-DD");
  },
  computed: {
    // 다크 모드 상태를 가져옴
    changeDarkMode() {
      return this.$store.getters.fnGetDark;
    },
  },
};
</script>

 

  • 폼 데이터 관리: writer, date, subject, content 등의 데이터는 v-model을 사용하여 폼 요소와 바인딩됩니다.
  • 폼 제출 처리: onSubmit 메소드는 폼 제출 이벤트를 처리하며, Vuex에 데이터를 저장하고 Q&A 목록 페이지로 이동합니다.
  • Vuex와의 연동: Vuex에서 현재 로그인한 사용자의 이름과 현재 날짜를 가져와 초기화합니다.

 

2. 게시글 목록 컴포넌트 (BoardList.vue)

<template>
  <div>
    <div class="board__title" :class="{ dark: changeDarkMode }">
      <h2>Q&amp;A</h2>
      <div class="write__wrapper">
        <router-link
          to="/qnawrite"
          class="goToWrite"
          :class="{ dark: changeDarkMode }"
          v-if="logined"
          >{{ $t("[3].boarddetail.writig") }}</router-link
        >
      </div>
    </div>
    <div class="boardList" :class="{ dark: changeDarkMode }">
      <table>
        <colgroup>
          <col />
          <col />
          <col />
          <col />
          <col />
        </colgroup>
        <thead>
          <tr :class="{ dark: changeDarkMode }">
            <th>{{ $t("[3].boarddetail.no") }}</th>
            <th>{{ $t("[3].boarddetail.title") }}</th>
            <th>{{ $t("[3].boarddetail.writer") }}</th>
            <th>{{ $t("[3].boarddetail.progress") }}</th>
            <th>{{ $t("[3].boarddetail.hit") }}</th>
          </tr>
        </thead>
        <tbody>
          <tr
            v-for="(item, idx) in qnaData[currentPage - 1]"
            :key="idx"
            :class="{ dark: changeDarkMode }"
          >
            <td>{{ item.id }}</td>
            <td>
              <router-link
                :to="{ name: 'qnadetail', params: { id: item.id } }"
                >{{ item.subject }}</router-link
              >
            </td>
            <td>{{ item.writer }}</td>
            <td v-if="!item.status">{{ $t("[3].boarddetail.waiting") }}</td>
            <td v-else>{{ $t("[3].boarddetail.completed") }}</td>
            <td>{{ item.hit }}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script>
export default {
  props: ["qnaData", "currentPage"],
  data() {
    return {
      logined: false,
    };
  },
  created() {
    this.logined = this.$store.getters.fnGetLogined;
  },
  computed: {
    changeDarkMode() {
      return this.$store.getters.fnGetDark;
    },
  },
};
</script>

 

  •  Q&A 목록 표시: v-for 디렉티브를 사용하여 qnaData 배열을 반복하여 게시글 목록을 생성합니다.
  • 라우터 링크 사용: router-link를 사용하여 각 게시글 제목을 클릭하면 해당 게시글의 상세 페이지로 이동하도록 설정합니다.
  •  로그인 상태 확인: created 훅에서 Vuex를 통해 현재 로그인 상태를 확인하고, 글쓰기 버튼을 조건부로 표시합니다.

 

 

3. Vuex 설정 (store/index.js 및 store/board/index.js)

게시판 데이터를 관리하기 위해 Vuex를 설정합니다.

 

store/index.js

import Vue from "vue";
import Vuex from "vuex";
import VuexPersistence from "vuex-persist";
import modTechTalks from "@/store/techtalks";
import modNews from "@/store/news";
import modDark from "@/store/dark";
import modAccount from "@/store/account";
import modboard from "@/store/board";

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    modTechTalks,
    modNews,
    modDark,
    modAccount,
    modboard,
  },
  plugins: [new VuexPersistence({ storage: window.localStorage }).plugin],
});

 

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,
  },
};

 

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

 

 

 

 

01
로그인 후 - 글쓰기 가능

 

q&a 작성