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> {{
$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&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 게터를 통해 상태를 접근합니다