Vue.js使って無料で一般公開されているAPIからデータを取得してきて、自分のサイトに表示させる方法について。
ビットコイン価格のAPIからデータを取得して表示するアプリを作成する手順についてまとめています。
接続するAPI
ここでは、実例用として、coindeskが無料で公開しているビットコイン価格のAPIを使用します。(公式ページにAPIのURLが記載してあります。)
▼APIのURL
使用するデータ
該当のURLを叩くと、次のようなデータにアクセスすることができます。
ここでは、このデータの中のbpiプロパティのUSDプロパティのrateを使用します。
bpiの価格を格納するプロパティを作成
初めに、ベースとなるhtmlファイルとjsファイルを作成します。
<body>
<div id="app">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="js/main.js"></script>
</body>
var app = new Vue({
el: '#app',
data:{
bpi: null
}
})
dataオプションの中にbpiというキー名を用意し、初期値となる値はnullとしておきます。
axiosの使用準備
axiosとは?
指定したWEBサイトからデータを取ってくるJSライブラリ。
┗ HTTP(WEB)クライアントと呼ぶ。
axiosの使い方
axiosを使うには、axiosのCDNのURLをscritpタグとして.htmlファイルのbodyタグ終端の上に貼り付けます。
最新バージョンを使用する場合
githubから、jsDeliverのCDNをコピーしてきます。
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
バージョンを固定する場合
jsDeliverの公式ページから直接CDNを取得。
「dist/axion.min.js」を使う。https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js
APIからデータを取得する
Vue.jsの処理の中にmountedプロパティを追加します。mountedはページを開く際に自動で実行する処理です。
mounted:function(){}
┗ mountedプロパティ
上記のfunctionの処理に axiosを使って指定したURLからデータを取得してくる処理を記述します。
axios.get('url').then(function(response)){処理}.bind(this)
┗ mountedプロパティの中でaxiosを使う
┗ 引数responseに取得データが格納される ※引数は任意(resなどでも可)
┗ データ使用は、引数名.data (response.data)
┗ .bind(this)でインスタンスと紐付ける
なお、.thisや.bindなど追加するメソッドは改行して記述することも可能です。
※注意点: .bind(this)は必須です。これでインスタンスと紐付けることで、dataプロパティと紐づきます。
var app = new Vue({
el: '#app',
data:{
bpi: null
},
mounted: function(){
axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(function(response){
this.bpi = response.data.bpi;
}.bind(this))
}
})
axiosを使って指定したURLのデータを取得し、それをVue.jsのdataプロパティで指定したbpiというデータの中に格納しています。
格納されているのは次のデータです。
bpi: {
USD: {
code: "USD",
symbol: "$",
rate: "42,674.8933",
description: "United States Dollar",
rate_float: 42674.8933
},
GBP: {
code: "GBP",
symbol: "£",
rate: "31,186.2573",
description: "British Pound Sterling",
rate_float: 31186.2573
},
EUR: {
code: "EUR",
symbol: "€",
rate: "37,352.5233",
description: "Euro",
rate_float: 37352.5233
}
}
以上でAPIからデータを取得してくる処理は完成です。
データが正しく取得できているか確認する
console.logを使ってデータが正しく取得できているか確認します。(chromeのdeveloperツールでのコンソールタブでデータ取得できているか確認できます)
・bpiデータの表示: console.log(response.data.bpi)
・USDの価格の表示: console.log(response.data.bpi.USD.rate_float)
var app = new Vue({
el: '#app',
data:{
bpi: null
},
mounted: function(){
axios.get('https://api.coindesk.com/v1/bpi/currentprice.json').then(function(response){
console.log(response.data.bpi);
console.log(response.data.bpi.USD.rate_float);
this.bpi = response.data.bpi;
}.bind(this))
}
})
出力結果
データが正しく取得できている場合、コンソールに次のように表示されます。
例外処理の設定(catch構文の追加)
データが取得できなかった場合の例外処理を追加します。
.catch(function(error){処理}
┗ 引数の名前は任意です。errorではなくerrもよく使用されます。
var app = new Vue({
el: '#app',
data:{
bpi: null
},
mounted: function(){
axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(function(response){
this.bpi = response.data.bpi
}.bind(this))
.catch(function(error){
console.log(error)
})
}
})
画面上に価格を表示
v-forで複数のプロパティデータを個々に取得し、マスタッシュ構文{{ }}で表示します。
▼v-forの使い方
v-for="(要素を入れる変数名, キー名) in 元のデータ名"
<body>
<div id="app">
<h2>ビットコイン価格</h2>
<ul>
<li v-for="(rate, currency) in bpi">
{{currency}} : {{rate.rate_float}}
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js"></script>
<script src="js/main.js"></script>
</body>
API経由で取得してきたデータを変数bpiに格納しています。v-forを使って変数bpiの中のデータを一つづつ取得しています。データのキー名(インデックス名)がcurrencyという変数に入り、値がrateという変数に入ります。
{{currency}} : {{rate.rate_float}}
でそれぞれのデータを表示してます。
rate.rate_floatとなっているのは、格納されているデータの中のrate_floatというデータを取得すると言う意味です。
例えばUSDの場合データは以下のようになっており、rate_floatで 42674.8933 が取得できます。
USD: {
code: "USD",
symbol: "$",
rate: "42,674.8933",
description: "United States Dollar",
rate_float: 42674.8933
},
ブラウザの表示例
ブラウザの表示は次のようになります。
小数点以下の調整(filterオプション)
Vue.jsの記述
Vue.jsではfilterオプションの中に処理を記述すると、それをHTMLファイルを読み込んだときにフィルターとして実行することができます。
フィルターは以下のような形で記述します。
filters:{
フィルター名(引数名){
return 処理
}
}
ここでは、フィルター名をcurrencyDecimalとし、toFixedメソッドを使った処理を記述し、小数点の桁数を指定します。
toFixed(数値)とすることで、対象の数値の小数点の桁数を指定した数値にすることができます。
var app = new Vue({
el: '#app',
data:{
bpi: null
},
mounted: function(){
axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(function(response){
this.bpi = response.data.bpi
}.bind(this))
.catch(function(error){
console.log(error)
})
},
//追記
filters:{
currencyDecimal(value){
return value.toFixed(2)
}
}
})
HTMLの記述
htmlファイルの中でfilterを呼び出すときは、{{対象のデータ | フィルタ名}}
とします。
こうすることで、対象のデータに指定したフィルタを実行した値が画面上に表示されます。
<body>
<div id="app">
<h2>ビットコイン価格</h2>
<ul>
<li v-for="(rate, currency) in bpi">
<!-- 追記 -->
{{currency}} : {{rate.rate_float | currencyDecimal}}
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js"></script>
<script src="js/main.js"></script>
</body>
(参考)Vue.js公式 filter
チラつき防止(v-cloak)
チラつきとは?
現状の状態では画面をロードしたときに一瞬コードが表示されてしまいます。これをチラつきと呼びます。
▼ブラウザの表示
ユーザーには関係のないデータなので、表示されないようにする必要があります。
v-cloakディレクティブを使用
チラつきはVue.jsのv-cloakを使うことで解消できます。
v-cloakとは画面の読み込みが完了が完了するまで、指定したcssを適用することです。
ここでは、画面の読み込みが完了するまでの間は何も表示せず、画面の読み込みが完了したらAPIで取得したデータを表示するようにします。
<body>
<div id="app">
<h2>ビットコイン価格</h2>
<!-- 追記 -->
<ul v-cloak>
<li v-for="(rate, currency) in bpi">
{{currency}} : {{rate.rate_float | currencyDecimal}}
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js"></script>
<script src="js/main.js"></script>
</body>
[v-cloak]{
display: none;
}
(参考)Vue.js公式 v-cloak
エラー時の表示分岐
v-ifとv-elseを使って、通信エラーが発生したときにエラー用テキストを表示する処理を追加します。
・v-if="真偽値"
とv-else
真偽値がtrueの場合: v-ifがある要素を表示する。
真偽値がfalseの場合: v-elseがある要素を表示する。
・dataオプションにhasErrorプロパティを設置(名称は任意)
┗ 初期値をfalseにし、正常表示のタグにv-elseを設置
・catch構文でエラー発生時に、hasErrorをtrueにする
┗ dataオプションと紐づけるため、.bind(this)
をつける。
var app = new Vue({
el: '#app',
data:{
bpi: null,
//追加
hasError: false
},
mounted: function(){
axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(function(response){
this.bpi = response.data.bpi
}.bind(this))
.catch(function(error){
console.log(error)
//追加
this.hasError = true
}.bind(this))
},
filters:{
currencyDecimal(value){
return value.toFixed(2)
}
}
})
<body>
<div id="app">
<h2>ビットコイン価格</h2>
<!-- 追加 -->
<section v-if="hasError">
通信エラーが発生しています。
</section>
<!-- 追加 -->
<section v-else>
<ul v-cloak>
<li v-for="(rate, currency) in bpi">
{{currency}} : {{rate.rate_float | currencyDecimal}}
</li>
</ul>
</section>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js"></script>
<script src="js/main.js"></script>
</body>
ローディング表示
通信中に以下のようにLoadingと表示する処理を追加します。
・dataオプションにloadingプロパティを追加(名称任意)
┗ 初期値:true
・axiosの通信終了後にloadingプロパティをfalseにする。.finally(function(){処理}.bind(this))
┗ .finally: 処理が終わったら実行
┗ .bind(this): dataプロパティと紐付ける
・テンプレートにv-ifで「loading…」を記述。
┗ v-if=”loading”で、trueの間のみ表示。
・正常な表示内容にv-else
を設置。
var app = new Vue({
el: '#app',
data:{
bpi: null,
hasError: false,
//追加
loading:true
},
mounted: function(){
axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(function(response){
this.bpi = response.data.bpi
}.bind(this))
.catch(function(error){
console.log(error)
this.hasError = true
}.bind(this))
//追加
.finally(function(){
this.loading = false
}.bind(this))
},
filters:{
currencyDecimal(value){
return value.toFixed(2)
}
}
})
<body>
<div id="app">
<h2>ビットコイン価格</h2>
<section v-if="hasError">
通信エラーが発生しています。
</section>
<section v-else>
<!-- 追加 -->
<div v-if="loading">
Loading...
</div>
<div v-else>
<ul v-cloak>
<li v-for="(rate, currency) in bpi">
{{currency}} : {{rate.rate_float | currencyDecimal}}
</li>
</ul>
</div>
</section>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js"></script>
<script src="js/main.js"></script>
</body>
以上で無料のAPIを使ったビットコイン価格表示アプリの作成は完了です。
完成版のコード一覧
最後に完成版のコード一覧を載せておきます。
使用したのは .html, .js, .cssファイルの3つです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bitcoin API</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div id="app">
<h2>ビットコイン価格</h2>
<section v-if="hasError">
通信エラーが発生しています。
</section>
<section v-else>
<!-- 追加 -->
<div v-if="loading">
Loading...
</div>
<div v-else>
<ul v-cloak>
<li v-for="(rate, currency) in bpi">
{{currency}} : {{rate.rate_float | currencyDecimal}}
</li>
</ul>
</div>
</section>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
var app = new Vue({
el: '#app',
data:{
bpi: null,
hasError: false,
//追加
loading:true
},
mounted: function(){
axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(function(response){
this.bpi = response.data.bpi
}.bind(this))
.catch(function(error){
console.log(error)
this.hasError = true
}.bind(this))
//追加
.finally(function(){
this.loading = false
}.bind(this))
},
filters:{
currencyDecimal(value){
return value.toFixed(2)
}
}
})
[v-cloak]{
display: none;
}
以上です。