Vue.jsでQiitaのホーム画面っぽいものを作ってみる

# はじめに

今回はVue.jsを使ってQiitaのホーム画面っぽいものを作ってみます。
Vueは簡単に作成できるフレームワークとして知られています。またAPIとの親和性が高く、一般公開されているAPIを使ってひょいっとページを作成することが可能です。

今回はこのような画面を作ってみます。Qiitaの新着記事の一覧を表示する画面です。

![スクリーンショット 2018-12-20 18.11.05.png](https://qiita-image-store.s3.amazonaws.com/0/151039/16eab446-3303-bec6-0b0d-9f29ba4741a0.png)


画面は１コンポーネントのみ、APIの読み込みにaxiosを使ってみます。早速セットアップからやってみましょう。

## Vue CLIのセットアップ

簡単にVue.jsの環境を作ることができるVue CLIのセットアップからですね。Nodejsがある環境が前提です。

```
npm install -g @vue/cli
vue create .
```

以下、質問に答えていくと、環境が整うはずです。

```
npm run serve
```

node_moduleに入っているパッケージを起動させます。
以下の画面が出れば成功です。開発を始めていきましょう。

![スクリーンショット 2018-12-20 18.33.54.png](https://qiita-image-store.s3.amazonaws.com/0/151039/c7f27513-5eca-f902-04b7-97405a4b34b9.png)

## 画面の作り込み

この画面はApp.vueに記載された画面が出ているのですが、今回は不要なのでその中の画面は一旦消してしまいます。  (参考のため別ファイルに名前を変更してもよいです。つまりApp.vueの空のファイルさえできていれば問題ありません)

さて、この状態だと何も表示されなくなるので、とりあえず`Helloworld`だけ出力しましょう。

ちなみに、単一コンポーネントについては、[vue-loader](https://vue-loader-v14.vuejs.org/ja/)このあたりで補足しながら読んでいくと良いでしょう。

Vueのコンポーネント単位での書き方は、この辺りです。
[コンポーネントの基本 — Vue.js](https://jp.vuejs.org/v2/guide/components.html)

App.vue

```vuejs
<template>
  <div>Hello World</div>
</template>
```

templateタグに入れたものはビューとしてページに反映されます。
左上に`Hello world`の文字が確認できたら大丈夫です。

![スクリーンショット 2018-12-18 17.27.49.png](https://qiita-image-store.s3.amazonaws.com/0/151039/9c08f8f8-d313-744b-7bfa-dec3680c3a87.png)

次はレイアウトですね。記事一覧ページっぽくなるようにスタイルを整えていきましょう。

```vuejs
<template>
  <div class="container">
    <ul class="articles">
      <li class="article">this is sample article</li>
    </ul>
  </div>
</template>

<style scoped>
  .container {
    width: 100%;
    height: 100vh;
    background: #dedede;
  }

  .articles {
    width: 600px;
    margin: 0 auto;
    background: white;
    list-style: none;
  }

  .article {
    height: 50px;
    padding: 6px;
    font-size: 16px;
    font-weight: bold;
  }
</style>
```

![スクリーンショット 2018-12-18 17.29.33.png](https://qiita-image-store.s3.amazonaws.com/0/151039/43bdba11-7df5-5df8-8b88-49b61673d176.png)

それらしきレイアウトにはなったでしょうか。もう少し調整が必要そうですね。実際のデータが欲しいので、API連携の方に移ります。

## API連携

https://qiita.com/api/v2/docs#get-apiv2items
こちらからデータを取得して画面に表示するまでをやってみます。
とりあえずscriptタグが機能するかどうかから見てみます。templateタグの下にscriptタグを書いて、その中に処理を書きます。

```vuejs
...
</template>

<script>
import axios from 'axios'

exports default {
  data() {
    console.log('sample log from scripts')
    return {}
  }
}

</script>
```

ページを更新して、DevToolsのconsoleを確認してみてください。
consoleに入力した文字が入っていれば成功です。

![スクリーンショット 2018-12-18 17.37.05.png](https://qiita-image-store.s3.amazonaws.com/0/151039/eb48e64e-2640-e15b-8afd-b31a3864da64.png)

次は実際のAPI連携ですね。
Qiita APIはGETのみであれば認証キーが不要です。(2018年12月現在)
https://qiita.com/api/v2/docs#get-apiv2items
先程掲載したこちらのリンクから、`https://qiita.com/api/v2/items`にアクセスして、その結果をconsoleで確認します。

```vuejs
<script>
import axios from 'axios'

export default {
  data() {
    console.log('sample log from scripts')
    return {}
  },
  mounted() {
    this.fetchArticles()
  },
  methods: {
    fetchArticles() {
      axios.get('https://qiita.com/api/v2/items')
        .then(res => {
          console.log(res)
        })
    }
  }
}
</script>
```

まず、mounted、つまりページのレンダリングが始まる前の時点でfetchArticles関数を走らせます。そのfetchArticle関数ではaxios.getでAPIに接続し、その結果をconsole.logで出力します。

ページを再読込みします。APIからのデータが取得できていればconsoleに出力されます。

![スクリーンショット 2018-12-18 17.57.35.png](https://qiita-image-store.s3.amazonaws.com/0/151039/3640c47c-7a01-b4e8-cca3-34dc55a7a47b.png)

dataに20個ほどの記事が配列になっているのが確認できます。次はその記事を表示させてみましょう。

```vuejs
<script>
import axios from 'axios'

export default {
  data() {
    return {
      articles: []
    }
  },
  mounted() {
    this.fetchArticles()
  },
  methods: {
    fetchArticles() {
      axios.get('https://qiita.com/api/v2/items')
        .then(res => {
          console.log(res)
          this.articles = res.data
        })
    }
  }
}
</script>
```

dataにarticlesを登録し、先ほど取得できていた記事一覧をその中に入れます。
そして、その中身を<template>に反映させます。v-forで、記事ごとにli要素の中に入れていきます。

```vuejs
<template>
  <div class="container">
    <ul class="articles">
      <li v-for="article in articles" :key="article.id" class="article">{{ article.title }}</li>
    </ul>
  </div>
</template>
```

確認します。

![スクリーンショット 2018-12-18 18.08.23.png](https://qiita-image-store.s3.amazonaws.com/0/151039/d6d2d92d-7cc0-5e9e-7b76-2eed62b04d1e.png)

タイトル一覧ができましたね。
そうしたら、残りのスタイルを組み立てていけば完了です。
スタイルを調節して、articleオブジェクトの中に、記事作成者のサムネイル、ユーザid, いいね数が出るようにして、記事をクリックしたらその記事を開くように変更しました。

```vuejs
<template>
  <div class="container">
    <ul class="articles">
      <li class="article">新着記事一覧</li>
      <li v-for="article in articles" :key="article.id" class="article">
        <img :src="article && article.user.profile_image_url" width="30" height="30" />
        <a :href="article && article.url" target="_blank" class="article-link">{{ article.title }}</a>
        <div class="article-detail">by {{ article && article.user.id }} 👍 {{ article.likes_count }} </div>
      </li>
    </ul>
  </div>
</template>

<style>
  .container {
    width: 100%;
    height: 100%;
    background: #eeeeee;
  }

  .articles {
    width: 600px;
    margin: 0px auto;
    background: white;
    list-style: none;
  }

  .article {
    min-height: 40px;
    padding: 10px;
    font-size: 14px;
    font-weight: bold;
    border-bottom: 1px solid #dedede;
  }

  .article-link {
    color: inherit;
    margin-left: 20px;
  }

  .article-link:hover {
    color: gray;
  }

  .article-detail {
    font-size: 11px;
    color: #9e9e9e;
  }
</style>
```

![スクリーンショット 2018-12-20 18.11.05.png](https://qiita-image-store.s3.amazonaws.com/0/151039/3faff848-bebd-8661-ef84-5056ae302426.png)


このようになりました。

## 最後に

今回はこのページにサムネイル、ページ遷移、作者名、いいね数を加えてqiitaっぽくしてみました。今回はここまでですが、かなり簡単にページを作れることがわかったかと思います。また、qiitaの他にもいろいろな箇所でAPIが公開されているので、そのAPIを使って画面を作ってみると良いと思います。最後に今回のファイルを貼っておきます。


```vuejs
<template>
  <div class="container">
    <ul class="articles">
      <li class="article">新着記事一覧</li>
      <li v-for="article in articles" :key="article.id" class="article">
        <img :src="article && article.user.profile_image_url" width="30" height="30" />
        <a :href="article && article.url" target="_blank" class="article-link">{{ article.title }}</a>
        <div class="article-detail">by {{ article && article.user.id }} 👍 {{ article.likes_count }} </div>
      </li>
    </ul>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  data() {
    console.log('sample log from scripts')
    return {
      articles: []
    }
  },
  mounted() {
    this.fetchArticles()
  },
  methods: {
    fetchArticles() {
      axios.get('https://qiita.com/api/v2/items')
        .then(res => {
          console.log(res)
          this.articles = res.data
        })
    }
  }
}
</script>

<style>
  .container {
    width: 100%;
    height: 100%;
    background: #eeeeee;
  }

  .articles {
    width: 600px;
    margin: 0px auto;
    background: white;
    list-style: none;
  }

  .article {
    min-height: 40px;
    padding: 10px;
    font-size: 14px;
    font-weight: bold;
    border-bottom: 1px solid #dedede;
  }

  .article-link {
    color: inherit;
    margin-left: 20px;
  }

  .article-link:hover {
    color: gray;
  }

  .article-detail {
    font-size: 11px;
    color: #9e9e9e;
  }
</style>
```