Vue PWA mylog

mylog 전체 보기

그랜파 개발자 2024. 11. 11. 16:22

Vue로 PWA 개발 - 그랜파 개발자

Vue 프로젝트 Beta Test : mylog, 일상의 기록

개발이 진행됨에 따라 소스 코드를 계속 추가해 갑니다.

 

처음 마이로그에 접속을 하면 홈페이지가 열립니다. 이 홈페이지에는 등록된 전체 마이로그의 목록을 나타냅니다.

 

마이로그 전체 보기

  1. 마이로그 전체 보기는 앱을 시작할 때 main.js에서 전체 마이로그를 로드하여 store의 mylogs state에 저장합니다.
  2. 홈페이지가 열리면 mylogs state에 저장된 마이로그 목록을 화면에 나타냅니다.
  3. 홈페이지 하단 footer에 생성일 순, 생성일 역순으로 정렬을 선택할 수 있는 아이콘이 있고, 이 아이콘은 HomeView.vue가 아니고 App.vue에 있습니다.
  4. 사용자가 마이로그 정렬 아이콘을 누르면 App.vue에서 전체 마이로그를 생성일 순, 또는 생성일 역순으로 로드하여 store의 mylogs state에 저장을 하면 HomeView는 state의 변화를 감지하여 변경된 마이로그 목록을 보여줍니다.
  5. 마이로그의 내용은 sanitize-html를 이용하여 안전한 HTML로 변경하여 화면에 나타냅니다.

 

1. sanitize-html

 

게시글, 댓글, 답글, 사용자 프로필 설명 등 사용자로부터 입력된 HTML이 필요한 경우, 이를 표시하기 전에 sanitizeHtml로 필터링합니다.

sanitizeHtml은 사용자로부터 입력된 HTML 콘텐츠에서 잠재적으로 위험하거나 불필요한 태그와 속성을 제거하여 안전하게 만드는 기능입니다. 주로 사용자가 입력한 HTML을 서버나 클라이언트에서 처리할 때 XSS(Cross-Site Scripting) 공격을 방지하기 위해 사용됩니다.

일반적으로 sanitizeHtml 라이브러리는 신뢰할 수 없는 콘텐츠에 포함된 악의적이거나 위험한 요소를 제거하거나 필터링하여, 웹페이지에 콘텐츠를 표시할 때 보안을 유지할 수 있도록 돕습니다.

sanitize-html 패키지는 Node.js 환경에서 사용할 수 있는 HTML 필터링 라이브러리입니다. npm 패키지 매니저를 사용하여 설치합니다.

npm install sanitize-html

 

2. 마이로그 로드

 

마이로그는 앱에 접속할 때 로드하여 store의 mylogs state에 저장합니다.

main.js

// src/main.js
. . .

new Vue({
  . . 
  created() {
    . . .
    dispatch('mylogs/fetchMylogs');
  }
}).$mount('#app')

 

3. 마이로그 정렬

src/App.vue

<!-- src/App.vue -->
<template>
  <v-app>
    . . .
    <v-footer app>
     . . .
      <v-btn class="ml-2" icon v-if="$route.name == 'home'" @click="orderByAsc">
        <v-icon>mdi-arrow-up</v-icon>
      </v-btn>

      <v-btn class="ml-2" icon v-if="$route.name == 'home'" @click="orderByDesc">
        <v-icon>mdi-arrow-down</v-icon>
      </v-btn>      
      . . .
    </v-footer>
  </v-app>
</template>

<script>
import { mapActions, mapGetters } from 'vuex';
import router from '@/router';  // Vue Router import

export default {
  name: 'App',

  . . .
  computed: {
    ...mapGetters('auth', ['user']),
   . . .
    }
  },
  methods: {
    ...mapActions('auth', [‘'logout']),
    ...mapActions('mylogs', ['fetchMylogs', 'fetchMylogsAsc']),
    . . .
    orderByDesc() { 
      this.fetchMylogs();
    },
    orderByAsc() { 
      this.fetchMylogsAsc();
    }
    . . .
  }
};
</script>

 

4. store

src/store/modules/mylogs.js

// src/store/modules/mylogs.js
import { db, doc, collection, getDoc, getDocs } from "@/firebase";
import { query, orderBy } from "@/firebase";

const state = {
  . . .
  mylogs: [],
};

const mutations = {
 . . .
  setMylogs(state, mylogs) {
    state.mylogs = mylogs;
  },
  . . .
};

const actions = {
  // 전체 마이로그를 작성일 역순으로 로드한다.
  async fetchMylogs({ commit }) {
    commit('setLoading', true);
    try {
      const mylogs = []; 
      const mylogsRef = query(collection(db, "mylogs"), orderBy("createdAt", "desc"));
      const querySnapshot = await getDocs(mylogsRef);
      querySnapshot.forEach((doc) => {
        // doc.data() is never undefined for query doc snapshots
        mylogs.push({ id: doc.id, ...doc.data() });
      });

      // state에 저장한다.
      commit('setMylogs', mylogs);

    } catch (error) {
      console.log("error: ", error);
      commit('setError', error);
    } finally {
      commit('setLoading', false);
    }
  },

  // 전체 마이로그를 작성일 순으로 로드한다.
  async fetchMylogsAsc({ commit }) {
    commit('setLoading', true);
    try {
      const mylogs = []; 
      const mylogsRef = query(collection(db, "mylogs"), orderBy("createdAt", "asc"));
      const querySnapshot = await getDocs(mylogsRef);
      querySnapshot.forEach((doc) => {
        // doc.data() is never undefined for query doc snapshots
        mylogs.push({ id: doc.id, ...doc.data() });
      });

      // state에 저장한다.
      commit('setMylogs', mylogs);

    } catch (error) {
      commit('setError', error);
    } finally {
      commit('setLoading', false);
    }
  },
  . . .
};

const getters = {
  . . .
  mylogs: state => state.mylogs
};

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
};

 

5. 마이로그 전체 보기

 

전체 마이로그는 앱이 열릴 때 로드 하여 mylogs state에 저장 하고, 홈 페이지(HomeView.vue) 가 열릴 때 state에 저장되어 있는 전체 마이로그 mylogs를 화면에 나타냅니다. 마이로그의 내용은 sanitizeContent 함수로 안전한 HTML로 변경한 후 화면에 나타냅니다.

src/views/HomeView.vue

<!-- src/views/HomeView.vue -->
<template>
  <v-container>
    
    . . . 

    <v-row>
      <v-col v-for="mylog in mylogs" :key="mylog.id" @click="viewMylog(mylog.id)" cols="12">
        <v-card>
          <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>
            <b>댓글</b> <span v-if="mylog.commentCount > 0"> {{mylog.commentCount }} </span> &nbsp;
            {{ mylog.userName }} . {{ formatDate(mylog.createdAt) }} 
            <span v-if="mylog.views > 0" > ({{ mylog.views }})</span>
          </v-card-subtitle>
        </v-card>
      </v-col>
    </v-row>
. . .

  </v-container>
</template>

<script>
import { mapActions, mapGetters } from "vuex";
import sanitizeHtml from 'sanitize-html';

export default {
  name:'HomeView',
  data() {
    return { 
    };
  },
  computed: {
    ...mapGetters('mylogs',['mylogs', 'error', 'loading'])
  },
  async created() {
  },
  methods: {
    ...mapActions('mylogs', ['resetError']),
    . . .
    // content를 안전한 html로 바꿔준다.
    sanitizeContent(content) {
      return sanitizeHtml(content.replace(/\n/g, '<br>'), {
        allowedTags: ['b', 'i', 'em', 'strong', 'p', 'br'],
        allowedAttributes: {}
      });
    },
  },
};
</script>

Vue PWA 프로젝트, mylog 코드

'Vue PWA mylog' 카테고리의 다른 글

mylog 수정  (1) 2024.11.14
mylog 상세보기  (2) 2024.11.13
mylog 계정  (0) 2024.11.11
mylog 로그인  (1) 2024.11.10
mylog 계정 만들기  (2) 2024.11.08