블로그 카테고리 관리
블로그에서 카테고리를 사용하면 다음과 같은 장점이 있습니다.
1. 콘텐츠 정리 및 구조화
비슷한 주제의 글을 그룹화하여 블로그가 체계적으로 정리됨
예: "프로그래밍", "라이프스타일", "여행", "요리" 등
사용자 입장: 원하는 주제를 빠르게 찾을 수 있음
블로그 운영자 입장: 콘텐츠를 쉽게 관리 가능
2. 사용자 경험(UX) 향상
방문자가 관심 있는 글을 쉽게 찾도록 유도
카테고리를 클릭하면 관련 글 목록을 바로 확인 가능
방문자가 블로그에서 더 오래 머무를 가능성이 증가
3. SEO(Search Engine Optimization) 최적화
카테고리별로 검색엔진에 최적화된 URL 구조 생성 가능
예:
- https://example.com/category/vue
- https://example.com/category/javascript
구조화된 데이터 제공 → 검색엔진이 블로그를 더 잘 이해함
검색 노출(트래픽) 증가 효과
4. 블로그 콘텐츠 확장 가능
새로운 주제를 추가하거나 기존 카테고리를 세분화 가능
예:
- "개발" → "웹 개발", "모바일 개발", "데이터 사이언스"
다양한 관심사를 가진 독자를 유입할 수 있음
5. 추천 및 필터 기능 강화
방문자가 특정 카테고리의 글을 더 많이 읽으면 추천 시스템 활용 가능
예:
- "프론트엔드" 글을 자주 보면, 관련 글 추천
맞춤형 콘텐츠 제공으로 재방문율 증가
6. 광고 및 수익 최적화
특정 카테고리에 맞는 광고를 배치하여 광고 효과 극대화 가능
예:
- "IT & 개발" → 프로그래밍 도서 광고
- "여행" → 항공권 및 호텔 광고
광고 수익 최적화 가능
결론
카테고리는 블로그의 콘텐츠를 체계적으로 정리하고,
사용자 경험을 향상시키며,
SEO 및 수익에도 긍정적인 영향을 줍니다.
myBlog 카테고리 관리
다양한 주제의 글을 쓸 수 있을 것이고,
또 어떤 주제의 글은 여러 개로 나눠서 작성할 수도 있습니다.
그래서 글의 카테고리가 있으면 좋습니다.
1. 카테고리 개발 요구 사항
블로그에 카테고리를 추가하기 위해 개발해야 할 내용들을 생각하여 봅시다.
- 사용자별로 카테고리가 다릅니다.
그러므로 사용자별 카테고리 등록할 수 있어야 합니다. - 등록된 카테고리의 전체 목록을 볼 수 있고,
- 등록된 카테고리를 선택하여 삭제할 수 있습니다.
- 등록된 카테고리를 삭제해도 등록된 글 속에 있는 카테고리는 삭제되지 않습니다.
그러므로 기본적으로 카테고리 없음에 대한 처리가 필요합니다. - 사용자의 블로그에서 카테고리를 선택하여 해당 카테고리의 글만 볼 수 있습니다.
- 삭제된 카테고리 등의 처리를 위하여 기본적으로 ‘카테고리 없음’에 대한 카테고리가 필요합니다.
- 글을 쓸 때에 카테고리를 선택합니다.
글을 저장하면 선택한 카테고리도 함께 저장이 됩니다.
2. 카테고리 관리
1. 카테고리 관리 컴포넌트
- 등록된 전체 카테고리 목록
- 새로운 카테고리의 등록
- 등록된 카테고리의 삭제
2. 사용자별 카테고리 관리
카테고리는 사용자 별로 관리됩니다.
그러므로 로그인 상태에서 카테고리를 등록할 수 있고,
카테고리 컬렉션에는 사용자를 구분할 수 있는 userId가 있어야 합니다.
3. 카테고리 개발
- DB : firestore
- 카테고리 컬렉션 : categories
- 카테고리 문서 항목 :
- id: 카테고리 Id (데이터베이스 자동 생성)
- category : 카테고리 이름
- userId : 사용자 Id
- 카테고리 데이터 처리
- 사용자 ID로 필터링된 카테고리 가져오기
const q = query( collection(db, "categories"), where("userId", "==", userId)
- 카테고리 저장
const docRef = await addDoc(collection(db, "categories"), {
name: newCategory, userId: userId,
});
- 카테고리 삭제
await deleteDoc(doc(db, "categories", id));
store의 post 모듈
// src/store/modules/post.js
import { v4 as uuidv4 } from 'uuid';
import { db, collection, getDocs, getDoc, setDoc, doc,
addDoc, updateDoc, deleteDoc, query, where, orderBy,
increment, arrayUnion } from "@/firebase";
const state = {
loading: false,
categories: [], // 카테고리
};
const mutations = {
setLoading(state, loading) {
state.loading = loading;
},
// 카테고리 관리
setCatogories(state, categories) { // 카테고리
state.categories = categories;
},
addCatogory(state, category) { // 카테고리 추가
state.categories.push(category);
},
removeCatogory(state, id) { // 카테고리 제거
let categories = [];
categories = state.categories.filter((category) => category.id !== id);
state.categories = categories;
},
};
const actions = {
// -- 카테고리 관리 ----
async fetchCategories({ commit }, { userId }) {
if (!userId) return;
try {
// 사용자 ID로 필터링된 카테고리 가져오기
const q = query(
collection(db, "categories"),
where("userId", "==", userId)
);
const querySnapshot = await getDocs(q);
let categories = [];
categories = querySnapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
// 로드한 카테고리를 상태에 저장한다.
commit("setCatogories", categories);
} catch (error) {
alert("Error fetching categories : " + error.message);
}
},
async addCategory({ commit }, { newCategory, userId } ) {
if (!newCategory || !userId) return;
try {
commit('setLoading', true);
const docRef = await addDoc(collection(db, "categories"), {
name: newCategory, userId: userId,
});
commit("addCatogory", { id: docRef.id, name: newCategory });
commit('setLoading', false);
} catch (error) {
alert("Error adding category : " + error.message);
}
},
async removeCategory({ commit }, id) {
try {
commit('setLoading', true);
await deleteDoc(doc(db, "categories", id)); // db에 저장된 카테고리 에서 제거
commit("removeCatogory", id); // state에 있는 카테고리에서 제거
commit('setLoading', false);
} catch (error) {
console.error("Error deleting category:", error);
}
},
};
const getters = {
};
export default {
namespaced: true,
state,
mutations,
actions,
getters
};
CategoryView.vue
<!-- src/views/CategoryView.vue -->
<template>
<v-container>
<v-row>
<v-col cols="12">
<v-card class="pa-4">
<v-card-title style="font-size:1.1em">카테고리 관리</v-card-title>
<!-- 새로운 카테고리 추가 -->
<v-text-field label="새 카테고리 추가" v-model="newCategory" @keyup.enter="doAddCategory"></v-text-field>
<v-card-actions class="mt-n4">
<v-spacer></v-spacer><v-btn color="primary" @click="doAddCategory">추가</v-btn>
</v-card-actions>
<v-list class="mt-n4">
<v-card-title style="font-size:1.1em">전체 카테고리</v-card-title>
<!-- Firestore에서 불러온 카테고리 -->
<v-list-item v-for="category in categories" :key="category.id">
<v-list-item-title style="font-size:1em">{{ category.name }}</v-list-item-title>
<v-btn icon @click="doRemoveCategory(category.id)">
<v-icon text>mdi-delete</v-icon>
</v-btn>
</v-list-item>
</v-list>
</v-card>
</v-col>
</v-row>
<div class="text-center">
<v-progress-circular v-if="loading" indeterminate></v-progress-circular>
</div>
</v-container>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
data() {
return {
newCategory: "", // 새로운 카테고리 입력 값
};
},
computed: {
...mapState('auth', ['profile']),
...mapState('post', ['categories', 'loading']),
},
methods: {
...mapActions('post', ['addCategory', 'removeCategory']),
async doAddCategory() {
if (!this.newCategory.trim()) return;
const userId = this.profile.userId;
this.addCategory({
newCategory: this.newCategory.trim(),
userId: userId
});
this.newCategory = ""; // 입력 필드 초기화
},
async doRemoveCategory(id) {
this.removeCategory(id);
},
},
};
</script>
'토이 프로젝트 - Vue, Firebase로 서버리스 PWA 개발' 카테고리의 다른 글
14. Vue(with Vuetify)와 Firebase로 서버리스 PWA myBlog 개발 - 블로그 글쓰기 (0) | 2025.02.14 |
---|---|
12. Vue(with Vuetify)와 Firebase로 PWA myBlog 개발 - OAuth 구글 계정으로 로그인 (0) | 2025.02.13 |
11. Vue(with Vuetify)와 Firebase로 서버리스 PWA myBlog 개발 - 계정 설정 (0) | 2025.02.11 |
10. Vue(with Vuetify)와 Firebase로 서버리스 PWA myBlog 개발 - Firestore (0) | 2025.02.11 |
9. Vue(with Vuetify)와 Firebase로 서버리스 PWA myBlog 개발 - 로그인 구현 (0) | 2025.02.09 |