【 Vue.js】無料APIを利用した、世界の為替とビットコイン価格一覧ページの作成方法

#【 Vue.js】無料APIを利用した、世界の為替とビットコイン価格一覧ページの作成方法

無料APIを使って、リアルタイムのビットコイン現在価格と為替（対日本円）の一覧を表示するページを作成する方法。


##完成図

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/83613e62-2200-7b0d-03c0-466b27919524.png)|
|:--|


**＜主な機能＞**
・日本円ビットコイン価格
・現在時刻の表示
・米ドルビットコイン価格
・日本円為替
・国コードとビットコイン価格、為替一覧表



##作成手順
1. [日本円ビットコイン価格の表示](#1-日本円ビットコイン価格の表示)
    1. [APIによるビットコイン価格の取得](#1-1-apiによるビットコイン価格の取得)
    2. [JPY/USD為替の取得](#1-2-jpyusd為替の取得)
    3. [現在時刻の取得](#1-3-現在時刻の取得)
    4. [四捨五入フィルタの作成](#1-4-四捨五入フィルタの作成)
    5. [1000桁区切りフィルタの作成](#1-5-1000桁区切りフィルタの作成)
    6. [テーブルの作成とスタイル調整](#1-6-テーブルの作成とスタイル調整)
2. [ビットコイン価格一覧表の表示](#2-ビットコイン価格一覧表の表示)
    1. [小数点桁数指定フィルタの作成](#2-1-小数点桁数指定フィルタの作成)
    2. [元データの確認](#2-2-元データの確認)
    3. [v-forによるデータ読み込み](#2-3-v-forによるデータ読み込み)
    4. [テーブルのスタイル調整](#2-4-テーブルのスタイル調整)
3. [確認用コード](#3-確認用コード)


<br>
##1. 日本円ビットコイン価格の表示
日本円ビットコイン価格の表示部を作成していく。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/1c739e25-daa9-46ec-27d6-ce4b27a04684.png)|
|:--|



<br>
###1-1 APIによるビットコイン価格の取得
####axios使用準備
まずは無料APIを使ってビットコイン価格を取得する。指定URLにアクセスしてデータを取得するために、**axiosというJavaScriptのライブラリ**を使用する。

axiosを使うためにはプロジェクト内へのインストールなど事前準備が必要。準備方法は下記ご参照。

・[Vue CLIでaxiosを使う方法](https://qiita.com/yuta-38/items/eb4ccf5b884d12db0a90)
・[通常のページでaxiosを使う方法](https://qiita.com/yuta-38/items/c7ec001b90669064eeb9#2-axios%E3%81%AEcdn%E3%82%92%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF%E3%81%A8%E3%83%87%E3%83%BC%E3%82%BF%E5%8F%96%E5%BE%97)


<br>
####mountedオプションでaxiosを使ってデータを取得する

▼axiosでデータを取得する方法
`axios.get('URL').then(function(res){処理}.bind(this))`

引数のresは任意。この変数に取得したデータを格納する。

・無料APIはcoindeskの下記エンドポイントを使用。
https://api.coindesk.com/v1/bpi/currentprice.json

<br>
取得できるデータは、リアルタイムのビットコイン価格のUSD, EUR、GBP（イギリス£）の３つのみのため、EURとJPYのリアルタイム為替を別途取得する必要がある。

ビットコイン価格取得するプログラムは下記になる。

```js:.js(script)
export default {
  name: 'BitcoinAPI',
  data: function(){
    return{
        //ビットコイン価格格納用
        bpi: null,
    }
  },
  mounted: function(){
    //ビットコイン現在価格取得
    axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
    .then(function(response){
    
        //デバッグ用
        console.log(response.data.bpi)
        this.bpi = response.data.bpi
    }.bind(this))
    
    //通信エラー用
    .catch(function(error){
        console.log(error)
    })
   }
}
```

※今回のプログラムはVue CLIのプロジェクトで作成しているため、export defaultやdataオプションの中にfunctionが記載されている。（根本的にはVue CLIを使わない場合も同様の考え方で問題ない）

・mountedオプションとは？
処理を実行するタイミングを指定するもので、Vueインスタンスを作成した後に実行される。

＞[Vueライフサイクルハック](https://jp.vuejs.org/v2/guide/instance.html)


・`this.bpi = response.data.bpi`とは？
取得したデータは変数responseに格納される。ビットコイン価格はdataプロパティの中の、bpiプロパティの中に入っている。（ここまではAPI側の設定）

これをdataオプションで定義した変数bpiに格納する。（こちら側の設定）



<br>
####1-2 JPY/USD為替の取得
上記APIで取得したビットコインの価格はEURのため、EURと日本円の為替を取得する。

APIは下記を使用。
https://api.exchangeratesapi.io/latest

※注意：為替はユーロベース
（登録不要で日本円/USDを取得できるAPIがあれば教えてください）

・日本円/EUR格納用に変数jpyEurを用意。
・日本円/USD格納用に変数jpyUsdを用意。
・ユーロベースのため、JPY/EURをUSD/EURで割ることで、JPY \USD価格を取得する。


```js:.js(script)
export default {
  name: 'BitcoinAPI',
  data: function(){
    return{
        jpyEur: '',
        jpyUsd: ''
    }
  },
  mounted: function(){
   //為替取得
 axios.get('https://api.exchangeratesapi.io/latest')
    .then(function(res){
        //デバッグ用
        console.log(res.data.rates)
        this.jpyEur = res.data.rates.JPY
        this.jpyUsd = res.data.rates.JPY/res.data.rates.USD
    }.bind(this))
    .catch(function(error){
        console.log(error)
    })
   }
}
```

*可読性向上のため、為替取得に必要なコードのみ記載。

・JPY/EURの為替
`res.data.rates.JPY`


・USD/EURの為替
`res.data.rates.USD`

・JPY/EURの為替
`res.data.rates.JPY/res.data.rates.USD`




<br>
###1-3 現在時刻の取得
データをロードしたタイミングの時刻を表示する。JavaScriptのnew Date()で現在時刻を生成し、toLocaleStringメソッドでマイクロ秒などの不要な部分をカット。

生成した時刻は変数nowに格納する。

```js:.js(script)
  data: function(){
    return{
        now: '',
    }
  },
  mounted: function(){
    //現在時刻取得
    this.now = new Date().toLocaleString()
   }
}
```







<br>
###1-4 四捨五入フィルタの作成
取得したビットコイン価格および、算出した数値は小数点を多く含むため、四捨五入するフィルタを作成する。

####フィルタの作成方法
グローバルで使えるフィルタを作成する。フィルタの作成はJSファイルで、Vue.filterを使い、フィルタ名と処理を記述する。

`Vue.filter('フィルタ名', function(value){return 処理}}`

Vue CLIでフィルタを作成する場合は、filterをモジュールとして作成し、main.jsでインポートする必要がある。

・[Vue CLIでフィルタを作成する方法](https://qiita.com/yuta-38/items/05bd470f80d4dfd2ae1a)
・[（参考）ローカルフィルタの作成方法](https://qiita.com/yuta-38/items/ad2fe37093158d600c4f#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%81%A8%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%90%E3%83%AB%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF)



####四捨五入フィルタの作成
四捨五入はJavaScriptのMath.roundメソッドを利用する。
`Math.round(数値)`

小数点の桁数を指定して四捨五入する場合は、その桁数を整数にするだけ10を掛け、四捨五入後に掛けた10の値で割る。

▼小数点2桁目で四捨五入する場合
`Math.round(value*100)/100`



```js:.js(script)
//小数点０桁目で四捨五入
Vue.filter('MathRound', function(value) {
  return Math.round(value);
})

//小数点1桁目で四捨五入
Vue.filter('MathRound1', function(value) {
  return Math.round(value*10)/10;
})

//小数点3桁目で四捨五入
Vue.filter('MathRound3', function(value) {
  return Math.round(value*1000)/1000;
})
```




<br>
###1-5 1000桁区切りフィルタの作成
日本円換算の１ビットコインの価格は100万前後と桁数が多いため、1000桁区切りするフィルタも作成する。

JavaScriptのtoLocaleStringメソッドを使用する。
`数値.toLocaleString()`

```js:.js(script)
Vue.filter('1000separator', function(value) {
  return value.toLocaleString();
})
```




<br>
###1-6 テーブルの作成とスタイル調整
表示するためのデータと下準備が整ったので、表を作成する。

表は２行×２列。縦をth(table head:見出しセル)とする。

＜テーブルの基本構造＞
tableタグの構造は階層構造をとる。最小構成はtableタグとtdタグ。その他は表の構造や可動性を考慮して設置する。

- table
    - tbody
    - thead
    - tfoot
        - tr
            - th
            - td


今回は、table > tbody > tr > th, tdタグの４種を使用。CSSスタイル適用のため、適当にclass, id名を振り分ける。


####表示するデータ
・データの表示はマスタッシュ展開{{}}を使用。
　 ┗ vueテンプレートの中でマスタッシュ展開を使うとデータを呼び出せる（データバインディング）。
・フィルタの適用はマスタッシュ展開の中でパイプ「|」＋フィルタ名。


- `bpi.EUR.rate_float * jpyEur` : 日本円ビットコイン価格
- `| MathRound`：四捨五入フィルタの適用
- `| 1000separator`：1000桁区切りフィルタの適用
- `bpi.USD.rate_float`：ビットコインUSD価格（小数点表示）
- `now` : 現在時刻の呼び出し
 


```html:.html(template)
      <h1>Bitcoin API</h1>
      <div id="wrapper">
        <div id="content-wrapper">
          <h2 class="table-title">ー 現在のビットコイン価格 ー</h2> 
          <table id="main-table"> 
            <tbody> 
              <tr id="first-tr"> 
                <th>現在値</th> 
                <td id="first-td"> 
                  <em>¥{{bpi.EUR.rate_float * jpyEur | MathRound | 1000separator}}</em> <span class="small-letter">({{now}})</span> 
                </td>
              </tr> 
              <tr>
                <th>米ドル</th> 
                <td><span id="doller-bit">${{bpi.USD.rate_float | MathRound | 1000separator}}</span><span class="small-letter">  ( ¥{{jpyUsd | MathRound1}}/USD )</span>
                </td>
                </tr>
            </tbody>
          </table> 
```


<br>
####cssの設定
テーブルに適用するcssは、外線を非表示にし、真ん中の線のみ点線にする。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/7bbf101a-f4d0-a536-8dd4-d1da4be8f5ab.png)|
|:--|


- `border-collapse: collapse;` : 枠線を１重線にする（デフォルトは２重線）
- `border:none;` : 枠線を非表示にする。
- `border-bottom: dashed 0.6px;` : 真ん中の線のみ点線にする。
    - dottedはより細かい点線になる。
    - 上段行のbottomにのみ適用する
- ` border-color: rgb(172, 172, 172);` : 薄いグレー

フォントサイズや太さは適宜調整。

```css:.css(style)
#wrapper{
  margin:60px 0;
}

.table-title{
  font-size:14px;
  color:rgb(72, 72, 72);
  font-weight: 400;
}

table{
  margin: 20px auto;
  text-align: left;
  border-collapse: collapse;
  border:none;
}
table th{
  font-size: 12px;
  font-weight: 400;
  padding:5px 10px;
}

#first-tr{
  border-bottom: dashed 0.6px;
  border-color: rgb(172, 172, 172);
}


td em{
  font-size:34px;
  font-weight: bold;
  font-style:normal;
}


.small-letter{
  font-size:12px;
}

#doller-bit{
  font-size:18px;
}
```

<br>
※[補足] Vue CLIで作成しているテンプレートのみにcssを適用するには、scoped属性をつける。

```css:.css(style)
<style scorped>

</style>
```




<br>
##2. ビットコイン価格一覧表の表示
国コードやビットコイン価格、為替の一覧を作成する。
「JPY/USD為替の取得」で取得した大元のデータの中にすべてのデータが含まれている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/a11f3936-fd63-b4ea-6879-6e95a9d462d4.png)



<br>
###2-1 小数点桁数指定フィルタの作成
データは既に取得済みなので、取得したデータを整形するため、小数点第２位表示にするフィルタを作成する。

JavaScriptのtoFixedメソッドを使用する。

`数値.toFixed(桁数)`

```js:.js(script)
Vue.filter('float2', function(value) {
  return value.toFixed(2);
})
```



<br>
###2-2 元データの確認
APIで取得したデータは複数のオブジェクトとして格納されている。

▼元データ
https://api.exchangeratesapi.io/latest

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/ae34b77d-d204-ba79-bb7f-f8f3d9fdd713.png)|
|:--|


ここでは変数exchangesに格納している。

```.js:js(script)
export default {
  data: function(){
    return{
        exchanges: '',
        jpyEur: '',
    }
  },
  mounted: function(){
    //為替取得
    axios.get('https://api.exchangeratesapi.io/latest')
    .then(function(res){
        this.exchanges = res.data.rates
        this.jpyEur = res.data.rates.JPY
    }.bind(this))
    .catch(function(error){
        console.log(error)
    })
  }
}  
```

　
<br>
###2-3 v-forによるデータ読み込み
v-forでは値とプロパティ名をそれぞれ一つづつ取り出すことができる。

`v-for="(値の変数名, プロパティの変数名 in オブジェクト)" v-bind:key="key"`
　┗ プロパティ名が後ろにくる。
　┗ 「v-bind:key="key"」：eslintのエラー対策で設置。

```html:.html(template)
              <tr class="exchange" v-for="(exchange, country) in exchanges" v-bind:key="key">
                <th>{{country}}</th>
                <td>{{exchange * bpi.EUR.rate_float | MathRound | 1000separator }}</td>
                <td>{{jpyEur/exchange | float2 }}</td>
              </tr>
```

・`country` : プロパティ名。すなわち国コードが入る。
・`exchange` : ユーロベースの為替。
・ `exchange * bpi.EUR.rate_float` : ユーロベースの為替とユーロベースのビットコイン価格を掛け合わせたもの。現地通貨でのビットコイン価格となる
・`jpyEur/exchange` : 対ユーロの日本円とユーロベースの為替を掛け合わせたもの。すなわち対日本円のその国の為替となる。
・`| MathRound` : 四捨五入フィルタ
・`| 1000separator` : 1000桁区切りフィルタ
・`| float2` : 小数点２桁表示


####表も合わせたhtmlコードは下記になる。


```html:.html(template)
<table id="table2" border="1">
            <tbody>
              <tr>
                <th>国コード</th>
                <th>ビットコイン価格（現地通過）</th>
                <th>為替（円）</th>
              </tr>
              <tr class="exchange" v-for="(exchange, key) in exchanges" v-bind:key="key">
                <th>{{key}}</th>
                <td>{{exchange * bpi.EUR.rate_float | MathRound | 1000separator }}</td>
                <td>{{jpyEur/exchange | float2 }}</td>
              </tr>
            </tbody>
          </table>
```



<br>
###2-4 テーブルのスタイル調整
ヘッダーとなる、最上部の行と、最前列に色付けを行う。



```css:.css(style)
table{
  margin: 20px auto;
  text-align: left;
  border-collapse: collapse;
  border:none;
}

table th{
  font-size: 12px;
  font-weight: 400;
  padding:5px 10px;
}


#table2{
  margin-top:100px;
  text-align: center;
}

#table2 tr:first-child{
  background: rgb(228, 228, 228);
}

.exchange th{
  background:rgba(255, 247, 215, 0.893);
}
```



<br>
##3. 確認用コード
全体のコードは以下となる。

```html:.html(template)
<template>
  <div>
      <h1>Bitcoin API</h1>
      <div id="wrapper">
        <div id="content-wrapper">
          <h2 class="table-title">ー 現在のビットコイン価格 ー</h2> 
          <table id="main-table"> 
            <tbody> 
              <tr id="first-tr"> 
                <th >現在値</th> 
                <td class="" id="first-td"> 
                  <em>¥{{bpi.EUR.rate_float * jpyEur　| MathRound | 1000separator}}</em> <span class="small-letter">({{now}})</span> 
                </td>
              </tr> 
              <tr>
                <th>米ドル</th> 
                <td><span id="doller-bit">${{bpi.USD.rate_float | MathRound | 1000separator}}</span><span class="small-letter">  ( ¥{{jpyUsd | MathRound1}}/USD )</span>
                </td>
                </tr>
            </tbody>
          </table> 
          
          <table id="table2" border="1">
            <tbody>
              <tr>
                <th>国コード</th>
                <th>ビットコイン価格（現地通過）</th>
                <th>為替（円）</th>
              </tr>
              <tr class="exchange" v-for="(exchange, key) in exchanges" v-bind:key="key">
                <th>{{key}}</th>
                <td>{{exchange * bpi.EUR.rate_float | MathRound | 1000separator }}</td>
                <td>{{jpyEur/exchange | float2 }}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
  </div>
</template>
```

```js:.js(scrypt)
<script>
import axios from 'axios'

export default {
  name: 'BitcoinAPI',
  data: function(){
    return{
        bpi: null,
        now: '',
        jpyEur: '',
        usdEur: '',
        jpyUsd: '',
        exchanges: ''
    }
  },
  mounted: function(){
    //ビットコイン現在価格取得
    axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
    .then(function(response){
        console.log(response.data.bpi)
        this.bpi = response.data.bpi
    }.bind(this))
    .catch(function(error){
        console.log(error)
    }),
    //現在時刻取得
    this.now = new Date().toLocaleString(),
    //為替取得
    axios.get('https://api.exchangeratesapi.io/latest')
    .then(function(res){
        console.log(res.data.rates)
        this.exchanges = res.data.rates
        this.jpyEur = res.data.rates.JPY
        this.usdEur = res.data.rates.USD
        this.jpyUsd = res.data.rates.JPY/res.data.rates.USD
    }.bind(this))
    .catch(function(error){
        console.log(error)
    })
  }
}  
</script>
```

```css:.css(style)
<style scorped>
#wrapper{
  margin:60px 0;
}

.table-title{
  font-size:14px;
  color:rgb(72, 72, 72);
  font-weight: 400;
}

table{
  margin: 20px auto;
  text-align: left;
  border-collapse: collapse;
  border:none;
}
table th{
  font-size: 12px;
  font-weight: 400;
  padding:5px 10px;
}

#first-tr{
  border-bottom: dashed 0.6px;
  border-color: rgb(172, 172, 172);
}


td em{
  font-size:34px;
  font-weight: bold;
  font-style:normal;
}


.small-letter{
  font-size:12px;
}

#doller-bit{
  font-size:18px;
}

#table2{
  margin-top:100px;
  text-align: center;
}

#table2 tr:first-child{
  background: rgb(228, 228, 228);
}

.exchange th{
  background:rgba(255, 247, 215, 0.893);
}

</style>
```


<br>
以上。