반응형
12장: 최종 프로젝트 - 미니 블로그 만들기
지금까지 배운 모든 기술(컴포넌트, Props, 반응성, Vue Router, Pinia)을 총동원하여 간단한 CRUD(Create, Read, Update, Delete) 기능이 있는 블로그 애플리케이션을 만듭니다.
1. 프로젝트 개요
만들 기능
- 글 목록 보기 (Read): 모든 게시글의 제목을 리스트 형태로 보여줍니다.
- 글 상세 보기 (Read): 특정 게시글의 제목과 내용을 상세하게 보여줍니다.
- 새 글 작성 (Create): 제목과 내용을 입력하여 새로운 글을 추가합니다.
- 글 수정 (Update): 기존 글의 제목과 내용을 수정합니다.
- 글 삭제 (Delete): 특정 글을 삭제합니다.
사용할 기술 스택
- UI: Vue 3 (Composition API)
- 라우팅: Vue Router
- 전역 상태 관리: Pinia
2. 단계별 구현 가이드
1단계: 프로젝트 구조 설정 및 라이브러리 설치
create-vue(Vite 기반)로 새 프로젝트를 생성합니다.
(설정 시npm create vue@latestVue Router와Pinia를 추가(Add)할지 묻는 질문에 Yes로 답하면 편리합니다.)- 필요한 라이브러리를 설치합니다. (위 과정에서 설치했다면 생략)
npm install vue-router pinia src폴더 내에components,pages(또는views),stores,router폴더 구조를 확인하거나 생성합니다.
2단계: 전역 상태(스토어) 설계 (stores/post.js)
Pinia를 사용하여 게시글 데이터를 관리하는 스토어를 만듭니다.
// src/stores/post.js
import { ref } from 'vue';
import { defineStore } from 'pinia';
export const usePostStore = defineStore('post', () => {
const posts = ref([
{ id: 1, title: 'Vue.js, 너는 대체...', content: 'Vue를 처음 배우는데 생각보다 재미있네요.' },
{ id: 2, title: 'Pinia 사용법', content: '전역 상태 관리가 이렇게 쉬울 줄이야!' },
]);
const nextPostId = ref(3);
// 새 글 추가
function addPost(postData) {
posts.value.push({ ...postData, id: nextPostId.value });
nextPostId.value++;
}
// 글 수정
function updatePost(updatedPost) {
const index = posts.value.findIndex(p => p.id === updatedPost.id);
if (index !== -1) {
posts.value[index] = updatedPost;
}
}
// 글 삭제
function deletePost(id) {
posts.value = posts.value.filter(p => p.id !== id);
}
return { posts, addPost, updatePost, deletePost };
});
3단계: 라우터 설정 (router/index.js)
Vue Router를 사용하여 페이지 경로를 설정합니다.
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import PostListPage from '../pages/PostListPage.vue';
import PostDetailPage from '../pages/PostDetailPage.vue';
import NewPostPage from '../pages/NewPostPage.vue';
import EditPostPage from '../pages/EditPostPage.vue';
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{ path: '/', name: 'PostList', component: PostListPage },
{ path: '/post/:id', name: 'PostDetail', component: PostDetailPage, props: true },
{ path: '/new-post', name: 'NewPost', component: NewPostPage },
{ path: '/edit-post/:id', name: 'EditPost', component: EditPostPage, props: true },
]
});
export default router;
4단계: 페이지 및 컴포넌트 구현
PostForm.vue(컴포넌트): 새 글 작성과 글 수정에서 재사용될 폼 컴포넌트입니다.PostListPage.vue(페이지):usePostStore에서posts배열을 가져와v-for로 렌더링합니다.PostDetailPage.vue(페이지):props로id를 받아 해당 게시글을 찾습니다. 수정/삭제 버튼을 포함합니다.NewPostPage.vue(페이지):PostForm을 사용하고, 제출 시addPost액션을 호출합니다.EditPostPage.vue(페이지):props로id를 얻어 기존 글 데이터를PostForm에 전달합니다. 제출 시updatePost액션을 호출합니다.
3. 연습 문제 및 도전 과제
문제 1: 댓글 기능 추가하기
- 요구사항:
postStore에 댓글 관련 상태와 액션을 추가하고,PostDetailPage에서 댓글을 보고 작성할 수 있게 만드세요. - 세부사항:
postStore의posts배열에 있는 각 post 객체에comments: []속성을 추가합니다.addComment(postId, commentText)액션을 스토어에 만듭니다. 이 액션은 해당postId를 가진 게시글을 찾아comments배열에 새 댓글을 추가해야 합니다.PostDetailPage에서 해당 게시글의comments를 리스트로 보여줍니다.PostDetailPage에 간단한 댓글 입력 폼을 만들고, 제출 시addComment액션을 호출합니다.
문제 1 힌트
// stores/post.js의 addComment 액션 예시
function addComment(postId, commentText) {
const post = posts.value.find(p => p.id === postId);
if (post) {
if (!post.comments) {
post.comments = [];
}
post.comments.push({ id: Date.now(), text: commentText });
}
}
문제 2: 검색 기능 추가하기
- 요구사항:
PostListPage에 검색창을 추가하여, 게시글 제목 기준으로 실시간 검색(필터링)이 되도록 만드세요. - 세부사항:
PostListPage컴포넌트에searchTerm이라는 로컬ref상태를 만듭니다.- 검색
input을 만들고,v-model로searchTerm상태와 연결합니다. computed속성을 사용하여,usePostStore에서 가져온posts배열을searchTerm으로 필터링한filteredPosts를 만듭니다.- 템플릿에서는
posts대신filteredPosts를v-for로 렌더링합니다.
문제 2 힌트
<!-- PostListPage.vue 내부 -->
<script setup>
import { ref, computed } from 'vue';
import { usePostStore } from '../stores/post';
const postStore = usePostStore();
const searchTerm = ref('');
const filteredPosts = computed(() => {
if (!searchTerm.value) {
return postStore.posts;
}
return postStore.posts.filter(post =>
post.title.toLowerCase().includes(searchTerm.value.toLowerCase())
);
});
</script>
<template>
<input v-model="searchTerm" placeholder="게시글 검색..." />
<!-- v-for="post in filteredPosts" ... -->
</template>
반응형
'프론트엔드 > 뷰' 카테고리의 다른 글
| [Vue] 11장: 전역 상태 관리 (Pinia) - 컴포넌트의 벽 허물기 (0) | 2025.09.23 |
|---|---|
| [Vue] 10장: Vue Router - 페이지 이동과 목차 만들기 (0) | 2025.09.23 |
| [Vue] 9장: 스타일링 - 컴포넌트에 옷 입히기 (0) | 2025.09.23 |
| [Vue] 8장: 컴포저블과 반응성 심화 - Vue 능력 끌어올리기 (0) | 2025.09.23 |
| [Vue] 7장: 폼과 `v-model` - 사용자의 입력 받기 (0) | 2025.09.23 |
| [Vue] 6장: 리스트 렌더링 - 동적인 목록 만들기 (0) | 2025.09.23 |
| [Vue] 5장: 조건부 렌더링 - 상황에 맞는 UI 보여주기 (0) | 2025.09.23 |
| [Vue] 4장: 이벤트 핸들링 - 사용자와의 상호작용 (0) | 2025.09.23 |