[Re:ゼロから始めるVue生活] Vueでもっと見るボタンを実装してみた

リストレンダリングというVueの機能を利用して
もっと見るボタンを実装してみました。

# 成果物
<img width="670" alt="スクリーンショット 2019-12-19 14.06.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393193/22c39288-069d-382d-a622-886924a5912a.png">
<img width="669" alt="スクリーンショット 2019-12-19 14.07.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393193/08bfe0cf-b62b-37ff-bc69-792cfbc2c458.png">


データをシンプルにするため、
とりあえずデータは5件、初期表示数は2件にします
また、ユーザー情報と投稿情報を同じ配列に入れます。
（phpのテーブル設計のようにユーザーと投稿を分けて処理させるのがいいかと思いますが
そこまでの技術がないのであくまで仮ということにします）

```js
data: {
    list: [
        { id: 1, userName: 'Aさん', thumbnailSrc: './img/ph1.jpg', message: 'メッセージAです', imageSrc: './img/ph1.jpg', created_at: '2019-12-19' },
        { id: 2, userName: 'Bさん', thumbnailSrc: './img/ph2.jpg', message: 'メッセージBです', imageSrc: './img/ph2.jpg', created_at: '2019-12-19' },
        { id: 3, userName: 'Cさん', thumbnailSrc: './img/ph3.jpg', message: 'メッセージCです', imageSrc: './img/ph3.jpg', created_at: '2019-12-19' },
        { id: 4, userName: 'Dさん', thumbnailSrc: './img/ph4.jpg', message: 'メッセージDです', imageSrc: './img/ph4.jpg', created_at: '2019-12-19' },
        { id: 5, userName: 'Eさん', thumbnailSrc: './img/ph5.jpg', message: 'メッセージEです', imageSrc: './img/ph5.jpg', created_at: '2019-12-19' },
    ],
    count: 2,
},
```

# vueの処理

```js

// 中略
computed: {
    listItems() {
        // dataのlistプロパティからcountプロパティ設定分に絞る
        const list = this.list
        return list.slice(0, this.count)
    }
},
methods: {
    // buttonをクリックするとcountが増えていく。結果listItemsの数が増えて表示されていく。
    isMore() {
        this.count += 2
    }
},
// 中略
```

# 表示

```html
<!--算出プロパティのlistItemsからループ表示-->
<div
    class="list-item"
    v-for="listItem in listItems"
    :key="listItem.id"
>
    <img v-if="listItem.imageSrc" :src="listItem.imageSrc" class="posts-image">
    <div class="text">
        <div class="created_at">{{ listItem.created_at }}</div>
        <div class="message">{{ listItem.message }}</div>
    </div>
    <div class="user">
        <img v-if="listItem.thumbnailSrc" :src="listItem.thumbnailSrc" class="user-image">
        <span>{{ listItem.userName }}</span>
    </div>
</div>

<!--listItemsの数からcount数を引いた時0以上ならボタン表示-->
<!--クリックするたびにmethodsのisMoreが発火-->
<button
    class="list-item-button"
    v-if="(listItems.length - count) >= 0"
    type="button"
    @click="isMore"
>
    もっと見る
</button>
```

# 完成形

```vue
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.17.1/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.5/lodash.min.js"></script>
<title>Vue App</title>
</head>
<body>
    <div id="app">
        <div class="contents">
            <div class="contents-item">
                <div
                    class="list-item"
                    v-for="listItem in listItems"
                    :key="listItem.id"
                >
                    <img v-if="listItem.imageSrc" :src="listItem.imageSrc" class="posts-image">
                    <div class="text">
                        <div class="created_at">{{ listItem.created_at }}</div>
                        <div class="message">{{ listItem.message }}</div>
                    </div>
                    <div class="user">
                        <img v-if="listItem.thumbnailSrc" :src="listItem.thumbnailSrc" class="user-image">
                        <span>{{ listItem.userName }}</span>
                    </div>
                </div>
            </div>
            <button
                class="list-item-button"
                v-if="(listItems.length - count) >= 0"
                type="button"
                @click="isMore"
            >
                もっと見る
            </button>
        </div>
    </div>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                list: [
                    { id: 1, userName: 'Aさん', thumbnailSrc: './img/ph1.jpg', message: 'メッセージAです', imageSrc: './img/ph1.jpg', created_at: '2019-12-19' },
                    { id: 2, userName: 'Bさん', thumbnailSrc: './img/ph2.jpg', message: 'メッセージBです', imageSrc: './img/ph2.jpg', created_at: '2019-12-19' },
                    { id: 3, userName: 'Cさん', thumbnailSrc: './img/ph3.jpg', message: 'メッセージCです', imageSrc: './img/ph3.jpg', created_at: '2019-12-19' },
                    { id: 4, userName: 'Dさん', thumbnailSrc: './img/ph4.jpg', message: 'メッセージDです', imageSrc: './img/ph4.jpg', created_at: '2019-12-19' },
                    { id: 5, userName: 'Eさん', thumbnailSrc: './img/ph5.jpg', message: 'メッセージEです', imageSrc: './img/ph5.jpg', created_at: '2019-12-19' },
                ],
                count: 2,
            },
            computed: {
                listItems() {
                    const list = this.list
                    return list.slice(0, this.count)
                }
            },
            methods: {
                isMore() {
                    this.count += 2
                }
            },
        });
    </script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            color: #696969;
            background: #313131;
        }
        .contents {
            margin: 50px;
        }
        .contents .contents-item {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
        }
        .contents .contents-item .list-item {
            width: 300px;
            margin: 20px 5px 10px;
            background: #fff;
            border-radius: 3px;
            filter: drop-shadow(0 0 2px rgba(0,0,0,0.3));
        }
        .contents .contents-item .list-item .posts-image {
            width: 100%;
            height: 150px;
            object-fit: cover;
            border-radius: 3px 3px 0 0;
            vertical-align: bottom;
        }
        .contents .contents-item .text {
            padding: 15px;
        }
        .contents .contents-item .text .created_at {
            font-size: 11px;
            color: rgb(179, 179, 179);
            margin: 0 0 5px 0;
        }
        .contents .contents-item .text .message {
            font-size: 13px;
            font-weight: bold;
        }
        .contents .contents-item .list-item .user {
            padding: 15px;
            border-top: 1px dashed #ccc;
        }
        .contents .contents-item .list-item .user .user-image {
            width: 30px;
            height: 30px;
            object-fit: cover;
            border-radius: 50%;
            vertical-align: bottom;
        }
        .contents .contents-item .list-item .user span {
            font-size: 11px;
            font-weight: bold;
            bottom: 5px;
            left: 5px;
            position: relative;
        }
        .contents .list-item-button {
            display: block;
            font-size: 14px;
            color: #ccc;
            margin: 50px auto;
            border: 0;
            background: none;
            transition: .5s;
        }
        .contents .list-item-button:hover {
            color: rgb(175, 0, 0);
        }
    </style>
</body>
</html>
```