Vue로 PWA 개발 - 그랜파 개발자
Vue 프로젝트 Beta Test : mylog, 일상의 기록
개발이 진행됨에 따라 소스 코드를 계속 추가해 갑니다.
mylog 내것 개선
카테고리가 생겼으니 내 마이로그를 볼 때에도 카테고리별로 볼 수 있습니다.
‘내것’ 페이지에서 카테고리를 선택하면 선택한 카테고리의 마이로그만 볼 수 있도록 수정합니다.
1. 카테고리 보이기
<!-- src/views/MyMyLogsView.vue -->
<template>
<v-container>
. . .
<v-row v-if="userMylogs.length > 0">
. . .
<v-card>
<!--카테고리-->
<v-card-text class="mb-n5" v-if="mylog.category" style="font-size:1em">
{{ mylog.category }}
</v-card-text>
<v-card-text class="mb-n5" v-else style="font-size:1em">
카테고리 없음
</v-card-text>
. . .
</v-card>
</v-col>
</v-row>
. . .
</v-container>
</template>
<script>
import { mapActions, mapState, mapGetters } from "vuex";
import sanitizeHtml from 'sanitize-html';
export default {
data() {
return {
myCategories: [],
selectedCategory: null, // 선택된 카테고리
};
},
computed: {
...mapGetters('mylogs',['userMylogs', 'loading']),
...mapState('mylogs', ['categories']),
. . .
}
},
methods: {
...mapActions('mylogs', ['fetchUserMylogs', 'fetchUserMylogsOrderByDateAsc', 'fetchUserMylogsOrderByViews','fetchCategories']),
. . .
},
mounted() {
const userId = this.$store.state.auth.user.id;
this.fetchCategories(userId); // Firestore에서 카테고리 데이터 가져오기
// 카테로그 이름만 가져온다.
//console.log(this.categories);
this.myCategories = this.categories.map(category => category.name);
this.myCategories.unshift('카테고리 없음');
this.myCategories.unshift('전체 보기');
//console.log(userId, this.selectedCategory);
this.fetchUserMylogs({userId, category:null}); // 본인 작성 글 가져오기
},
};
</script>
2. 카테고리 로드
// src/store/modules/mylogs.js
async fetchCategories({ commit }, userId) {
if (!userId) return;
try {
// 사용자 ID로 필터링된 카테고리 가져오기
const q = query( collection(db, "categories"), where("userId", "==", userId) );
const querySnapshot = await getDocs(q);
// DB에서 로드한 카테고리를 배열에 넣는다.
let categories = [];
categories = querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
// 로드한 카테고리를 상태에 저장한다.
commit("setCatogories", categories);
} catch (error) {
console.error("Error fetching categories:", error);
}
},
3. MyMyLogsView.vue
<!-- src/views/MyMyLogsView.vue -->
<template>
<v-container>
<v-row>
<v-col><v-card-title style="font-size:1em">{{ getMylogName }}</v-card-title></v-col>
</v-row>
<v-row class="mt-n5">
<v-col >
<v-select class="mt-2" v-model="selectedCategory" :items="myCategories"
label="카테고리를 선택하세요" outlined dense @change="onItemChange">
</v-select>
<span style="text-align: right">
<v-btn text @click="viewByDateDesc">최신순</v-btn>
<v-btn text @click="viewByDateAsc">오래된순</v-btn>
<v-btn text @click="viewByViews">조회순</v-btn>
</span>
</v-col>
</v-row>
<v-row v-if="userMylogs.length > 0">
<v-col v-for="mylog in userMylogs" :key="mylog.id" @click="goToMylogDetail(mylog.id)" cols="12">
<v-card>
<!--카테고리-->
<v-card-text class="mb-n5" v-if="mylog.category" style="font-size:1em">
{{ mylog.category }}
</v-card-text>
<v-card-text class="mb-n5" v-else style="font-size:1em">
카테고리 없음
</v-card-text>
<v-card-title style="font-size:1em">{{ mylog.title }}</v-card-title>
<!-- eslint-disable -->
<v-card-text style="font-size:1em" class="mt-n2 mb-n6" v-html="sanitizeContent(mylog.content)"></v-card-text>
<!-- eslint-enable -->
<v-card-subtitle>
<span v-if="mylog.commentCount> 0" style="cursor: pointer">댓글 {{mylog.commentCount }} </span>
{{ mylog.userName }} . {{ formatDate(mylog.createdAt) }}
<span v-if="mylog.views > 0" > ({{ mylog.views }})</span>
</v-card-subtitle>
</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 { mapActions, mapState, mapGetters } from "vuex";
import sanitizeHtml from 'sanitize-html';
export default {
data() {
return {
myCategories: [],
selectedCategory: null, // 선택된 카테고리
};
},
computed: {
...mapGetters('mylogs',['userMylogs', 'loading']),
...mapState('mylogs', ['categories']),
getMylogName() {
return this.$store.state.auth.user.mylogname;
}
},
methods: {
...mapActions('mylogs', ['fetchUserMylogs', 'fetchUserMylogsOrderByDateAsc', 'fetchUserMylogsOrderByViews','fetchCategories']),
goToMylogDetail(mylogId) {
this.$router.push({ name: 'mylog', params: { id: mylogId } });
},
// 본인 작성 글 가져오기 - 최신순
viewByDateDesc() {
const userId = this.$store.state.auth.user.id;
if(this.selectedCategory == "전체 보기")
this.fetchUserMylogs({userId, category:null});
else
this.fetchUserMylogs({userId, category: this.selectedCategory});
},
// 본인 작성 글 가져오기 - 오래된 순
viewByDateAsc() {
const userId = this.$store.state.auth.user.id;
if(this.selectedCategory == "전체 보기")
this.fetchUserMylogsOrderByDateAsc({userId, category:null});
else
this.fetchUserMylogsOrderByDateAsc({userId, category: this.selectedCategory});
},
// 본인 작성 글 가져오기 - 조회순
viewByViews() {
const userId = this.$store.state.auth.user.id;
if(this.selectedCategory == "전체 보기")
this.fetchUserMylogsOrderByViews({userId, category:null});
else
this.fetchUserMylogsOrderByViews({userId, category: this.selectedCategory});
},
// content를 안전한 html로 바꿔준다.
sanitizeContent(content) {
return sanitizeHtml(content.replace(/\n/g, '<br>'), {
allowedTags: ['b', 'i', 'em', 'strong', 'p', 'br'],
allowedAttributes: {}
});
},
formatDate(date) {
if (date && date.toDate) {
return date.toDate().toISOString().replace('T', ' ').substring(0, 16);
}
return '';
},
onItemChange(category) {
//console.log("선택값이 변경되었습니다:", category);
const userId = this.$store.state.auth.user.id;
if(category == "전체 보기")
this.fetchUserMylogs({userId, category:null});
else
this.fetchUserMylogs({userId, category});
},
},
mounted() {
const userId = this.$store.state.auth.user.id;
this.fetchCategories(userId); // Firestore에서 카테고리 데이터 가져오기
// 카테로그 이름만 가져온다.
//console.log(this.categories);
this.myCategories = this.categories.map(category => category.name);
this.myCategories.unshift('카테고리 없음');
this.myCategories.unshift('전체 보기');
//console.log(userId, this.selectedCategory);
this.fetchUserMylogs({userId, category:null}); // 본인 작성 글 가져오기
},
};
</script>
Vue PWA 프로젝트, mylog 코드
'Vue PWA mylog' 카테고리의 다른 글
mylog 모아보기 개선 (0) | 2024.12.05 |
---|---|
mylog 쓰기 개선 (1) | 2024.12.03 |
mylog 카테고리 (0) | 2024.12.02 |
mylog FCM 받기 (1) | 2024.12.01 |
mylog FCM 보내기 (0) | 2024.11.30 |