シンプルブログ、記事詳細ページの作成

Vue.js

概要

DRFとVue.jsで、シンプルブログを作るシリーズの一つです。記事詳細ページを作成していきます。

URLの定義

router/index.jsに、URLの定義を追加します。

// 追加
import Post from '@/components/Post.vue'


const routes = [
    // 追加
    {
        path: '/detail/:id',
        name: 'detail',
        component: Post,
        props: routes => ({
            id: Number(routes.params.id),
        })
    },
]

/detail/2 のようなURLで、詳細ページが表示されます。2といった部分は記事のidですね。propsオプションでは、idを数値に必ず変換するようにしています。しなくても今のところ動くのですが、しておくことにします。

記事コンポーネント

上で定義したPostコンポーネントを作っていきます。components/Post.vueを作ります。

<template>
    <article class="container" v-if="post">
        <nav id="back"><a href="/" title="前ページへ戻る"><img src="@/assets/back.png"></a></nav>
        <p class="post-category" :style="{'color': post.category.color}">{{post.category.name}}</p>
        <h1 class="post-title">{{post.title}}</h1>
        <p class="post-lead">{{post.lead_text}}</p>
        <hr class="divider">
        <div class="post-main">{{ post.main_text }}</div>
        <hr class="divider">
        <nav id="top"><a @click="scrollTop" title="一番上まで戻る"><img src="@/assets/ue.png"></a></nav>
    </article>
</template>

<script>
    export default {
        name: 'post',
        props: {
            id: {type: Number},
        },
        data() {
            return {
                post: null,
            }
        },
        created() {
            this.$http(`${this.$httpPosts}${this.id}/`)
                .then(response => {
                    return response.json()
                })
                .then(data => {
                    this.post = data
                })
        },
        methods: {
            scrollTop() {
                window.scrollTo({
                    top: 0,
                    behavior: "smooth"
                });
            }
        }
    }
</script>

<style scoped>
    #back {
        margin-bottom: 80px;
    }

    #back a {
        cursor: pointer;
        width: 44px;
        display: inline-block;
    }

    #top a {
        cursor: pointer;
        color: #999;
        display: inline-block;
        width: 44px;
    }

    .post-category {
        font-size: 12px;
    }

    .post-title {
        font-weight: bold;
        font-size: 14px;
    }

    .post-lead {
        margin-top: 10px;
    }

    .divider {
        margin-top: 80px;
        margin-bottom: 80px;
        width: 100%;
        height: 1px;
        border: none;
        background-color: #ccc;
    }

    .post-main {
        width: 100%;
        line-height: 2;
    }

    .post-main p {
        margin-bottom: 4em;
    }

    .post-main img {
        max-width: 100%;
        height: auto;
        box-shadow: 0 0 5px #ccc;
    }

    @media (min-width: 768px) {
        .post-title {
            width: 440px;
        }

        .post-lead {
            width: 440px;
        }

        .divider {
            width: 650px;
        }

        .post-main {
            width: 650px;
        }
    }
</style>

propsオプションでidを受け取れるようにして、createdではそのidを使って記事詳細データをAjaxで取得します。取得したら、dataオプションのpostプロパティにそれを設定し、それによって記事部分のHTMLが反映されます。単体の記事データに関しては、Vuexではなくコンポーネント自身で管理するのが直感的に見えます。

scrollTopメソッドは、押すと一番上まで戻るやつですね。

記事一覧からのリンクを張る

最後に、PostList.vueを編集して、各記事をクリックして詳細ページに移動するようにしましょう。記事部分を<router-link>で囲むようにします。

            <router-link :to="{name: 'detail', params: {id: post.id}}" v-for="post of postList" :key="post.id"
                         class="post">
                <article>
                    <figure>
                        <img :src="post.thumbnail" :alt="post.title" class="thumbnail">
                    </figure>
                    <p class="post-category" :style="{'color': post.category.color}">{{post.category.name}}</p>
                    <h2 class="post-title">{{post.title}}</h2>
                    <p class="post-lead">{{post.lead_text}}</p>
                </article>
            </router-link>

:to="{name: 'detail', params: {id: post.id}}"はURLの逆引きを行っています。nameがdetailで、idを受け取る定義を探してくれて、そしてURLを組み立ててくれます。

Relation Posts

Comment

記事にコメントする

まだコメントはありません。