PWA

ChatGPT와 함께 PWA Blog 개발 - 글 상세보기

그랜파 개발자 2024. 8. 15. 05:19

53. 글 상세보기

ChatGPT에게 물었습니다.

Implement a function so that you can view details by clicking on a title in the list.

리스트에서 제목을 클릭하면 상세하게 볼 수 있도록 기능을 구현해줘.

To implement a function that allows viewing details of a post by clicking on its title in the list, you need to:
목록에서 제목을 클릭하여 게시물의 세부정보를 볼 수 있는 기능을 구현하려면 다음을 수행해야 합니다.

  1. Add a new route for displaying the post details.
    게시물 세부정보를 표시하기 위한 새 경로를 추가합니다.
  2. Create a Vue component for displaying the post details.
    게시물 세부 정보를 표시하기 위한 Vue 구성 요소를 만듭니다.
  3. Update the post list component to link to the post details view.
    게시물 세부정보 보기에 연결되도록 게시물 목록 구성요소를 업데이트합니다.

Here's how you can do it:
방법은 다음과 같습니다.

1. Add a New Route for Post Details

Update your router to include a route for the post details view.
게시물 세부정보 보기에 대한 경로를 포함하도록 라우터를 업데이트하세요.

 

router/index.js

import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import PostListView from '../views/PostListView.vue';
import PostDetailView from '../views/PostDetailView.vue';
import Login from '../views/Login.vue';
import WritePost from '../views/WritePost.vue';
import store from '../store';

Vue.use(VueRouter);

const routes = [
  { path: '/', name: 'Home', component: Home },
  { path: '/login', name: 'Login', component: Login },
  { 
    path: '/write-post', 
    name: 'WritePost', 
    component: WritePost, 
    meta: { requiresAuth: true } 
  },
  { 
    path: '/post-list', 
    name: 'PostListView', 
    component: PostListView, 
    meta: { requiresAuth: true } 
  },
  {
    path: '/post/:id',
    name: 'PostDetailView',
    component: PostDetailView,
    meta: { requiresAuth: true }
  }
];

const router = new VueRouter({
  routes
});

router.beforeEach((to, from, next) => {
  const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
  const user = store.state.auth.user;

  if (requiresAuth && !user) {
    next('/login');
  } else {
    next();
  }
});

export default router;

2. Create a Vue Component for Post Details

Create a new component to display the details of a post.
게시물의 세부정보를 표시하는 새 구성요소를 만듭니다.

 

views/PostDetailView.vue

<template>
  <v-container>
    <v-alert v-if="error" type="error" dismissible>{{ error.message }}</v-alert>
    <v-progress-circular v-if="loading" indeterminate></v-progress-circular>
    <v-card v-if="!loading && post">
      <v-card-title>{{ post.title }}</v-card-title>
      <v-card-text>{{ post.content }}</v-card-text>
    </v-card>
  </v-container>
</template>

<script>
import { db } from '../firebase';

export default {
  data() {
    return {
      post: null,
      loading: false,
      error: null
    };
  },
  async created() {
    this.loading = true;
    const postId = this.$route.params.id;
    try {
      const postDoc = await db.collection('posts').doc(postId).get();
      if (postDoc.exists) {
        this.post = postDoc.data();
      } else {
        this.error = { message: 'Post not found' };
      }
    } catch (error) {
      this.error = error;
    } finally {
      this.loading = false;
    }
  }
};
</script>

3. Update the Post List Component to Link to the Post Details View

Update the post list component to include a link to the post details view.
게시물 세부정보 보기에 대한 링크를 포함하도록 게시물 목록 구성요소를 업데이트합니다.

 

components/PostList.vue

<template>
  <v-container>
    <v-alert v-if="error" type="error" dismissible>{{ error.message }}</v-alert>
    <v-progress-circular v-if="loading" indeterminate></v-progress-circular>
    <v-list v-if="!loading && posts.length">
      <v-list-item v-for="post in posts" :key="post.id" @click="goToPostDetail(post.id)">
        <v-list-item-content>
          <v-list-item-title>{{ post.title }}</v-list-item-title>
          <v-list-item-subtitle>{{ post.content }}</v-list-item-subtitle>
        </v-list-item-content>
      </v-list-item>
    </v-list>
    <v-alert v-if="!loading && !posts.length" type="info">No posts available</v-alert>
  </v-container>
</template>

<script>
import { db } from '../firebase';

export default {
  data() {
    return {
      posts: [],
      loading: false,
      error: null
    };
  },
  async created() {
    this.loading = true;
    try {
      const postsSnapshot = await db.collection('posts').get();
      const posts = [];
      postsSnapshot.forEach(doc => {
        posts.push({ id: doc.id, ...doc.data() });
      });
      this.posts = posts;
    } catch (error) {
      this.error = error;
    } finally {
      this.loading = false;
    }
  },
  methods: {
    goToPostDetail(postId) {
      this.$router.push({ name: 'PostDetailView', params: { id: postId } });
    }
  }
};
</script>

4. Integrate Everything

Make sure to import and use the PostList component in your PostListView.vue.
PostListView.vue에서 PostList 구성 요소를 가져와 사용해야 합니다.

 

views/PostListView.vue

<template>
  <v-container>
    <post-list></post-list>
  </v-container>
</template>

<script>
import PostList from '../components/PostList.vue';

export default {
  components: {
    PostList
  }
};
</script>

With these steps, you have implemented a function to view details of a post by clicking on its title in the list. The PostList component now links to the PostDetailView component, which displays the post's details.

이러한 단계를 통해 목록에서 제목을 클릭하여 게시물의 세부정보를 볼 수 있는 기능을 구현했습니다. 이제 PostList 구성 요소는 게시물의 세부 정보를 표시하는 PostDetailView 구성 요소에 연결됩니다.

ChatGPT가 시키는 대로 했습니다.

1. router/index.js

2. views/PostDetailView.vue

3. components/PostList.vue

이것은 HomeView.vue 입니다.

4. 실행

Source Code

1. rc/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '@/views/HomeView.vue';
import LoginView from '@/views/LoginView.vue';
import RegisterView from '@/views/RegisterView.vue';
import ProfileView from '@/views/ProfileView.vue';
import AboutView from '@/views/AboutView.vue';
import auth from '../store/modules/auth';

import PostForm from '@/components/PostForm.vue';
import PostDetailView from '@/views/PostDetailView.vue';

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'HomeView',
    component: HomeView
  },
  {
    path: '/post/:id',
    name: 'PostDetailView',
    component: PostDetailView,
    meta: { requiresAuth: true }
  },
  {
    path: '/postForm',
    name: 'PostForm',
    component: PostForm
  },
  {
    path: '/login',
    name: 'LoginView',
    component: LoginView
  },
  {
    path: '/register',
    name: 'RegisterView',
    component: RegisterView
  },
  {
    path: '/profile',
    name: 'ProfileView',
    component: ProfileView,
    meta: { requiresAuth: true }
  },
  {
    path: '/about',
    name: 'AboutView',
    component: AboutView
  }
];

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
});

router.beforeEach((to, from, next) => {
  const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
  const isAuthenticated = auth.getters.isAuthenticated;
  if (requiresAuth && !isAuthenticated) {
    next('/login');
  } else {
    next();
  }
});

export default router;

2. views/PostDetailView.vue

<!-- views/PostDetailView.vue -->
<template>
  <v-container>
    <v-alert v-if="error" type="error" dismissible>{{ error.message }}</v-alert>
    <v-progress-circular v-if="loading" indeterminate></v-progress-circular>
    <v-card v-if="!loading && post">
      <v-card-title>{{ post.title }}</v-card-title>
      <v-card-text>{{ post.content }}</v-card-text>
    </v-card>
  </v-container>
</template>

<script>
import { db } from '../firebase';

export default {
  data() {
    return {
      post: null,
      loading: false,
      error: null
    };
  },
  async created() {
    this.loading = true;
    const postId = this.$route.params.id;
    try {
      const postDoc = await db.collection('posts').doc(postId).get();
      if (postDoc.exists) {
        this.post = postDoc.data();
      } else {
        this.error = { message: 'Post not found' };
      }
    } catch (error) {
      this.error = error;
    } finally {
      this.loading = false;
    }
  }
};
</script>

3. src/components/HomeView.vue

Copy<!-- src/viewa/HomeView.vue -->
<template>
  <v-container>
    <v-alert v-if="error" type="error" dismissible>{{ error.message }}</v-alert>
    <v-progress-circular v-if="loading" indeterminate></v-progress-circular>
    <v-list v-if="!loading && posts.length">
      <v-list-item v-for="post in posts" :key="post.id" @click="goToPostDetail(post.id)">
        <v-list-item-content>
          <v-list-item-title>{{ post.title }}</v-list-item-title>
          <v-list-item-subtitle>{{ post.content }}</v-list-item-subtitle>
        </v-list-item-content>
      </v-list-item>
    </v-list>
    <v-alert v-if="!loading && !posts.length" type="info">No posts available</v-alert>
  </v-container>
</template>

<script>
export default {
  name: 'Home',
  computed: {
    posts() {
      return this.$store.state.posts.posts;
    },
    loading() {
      return this.$store.state.posts.loading;
    },
    error() {
      return this.$store.state.posts.error;
    }
  },
  created() {
    this.$store.dispatch('posts/fetchPosts');
  },
  methods: {
    goToPostDetail(postId) {
      this.$router.push({ name: 'PostDetailView', params: { id: postId } });
    }
  }
};
</script>