Vue.js:JSONファイルをAJAXで取得して表示する


最近また Javascript を書いています。
Chrome拡張のメンテナンスをしたい気持ちもありますが、最近盛り上がっている Vue.js を使ってみました。

モダンなウェブアプリケーション開発と言えば React.js ですが、どうしても JSXに違和感があったり、
そもそもいきなり大規模でリアクティブなアプリケーションを作るつもりも無かったので、小規模な開発からも
使えて、使いやすいと評判の Vue.js です。最初に書いておくと、Vue.js かなりいいですよ。

データをテンプレートに展開するようなデータバインディングは、ガイドを見れば十分だと思うので、
もう少し実践的なものにしようと思います。

Vue.js で AJAX

実は、Vue.js そのものは Ajax をサポートしていません。
以前は vue-resource というパッケージが公式のライブラリという扱いだったようなのですが、
現在は公式推奨では無くなっています。

vue-resource の引退について

Ajax は jQuery でも何でも使えばいいじゃないという状態で、vue-resource の代わりとして axios を使うといいよ、
という案内がありました。まあ、こだわりは無いので axios を使ってみます。

axios の README に書いてある事そのままですが、

axios.get('リクエスト先URL')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

こんな感じでデータ取得が可能です。簡単ですね。

適当なJSONを取ってくる

ここらへんや
http://www.data.go.jp/
ここらへんを
http://linkdata.org/
ざっと見てみたのですが、データは JSON で配布されているものの、Access-Control-Allow-Origin ヘッダが付いている
サイトはあまりありません。いわゆるクロスドメイン問題ですね。Javascript から直接リクエストを飛ばすと弾かれます。
(まあ、JSONファイルを落としてきて同一サイトに置いてしまえば解決する話ですが)

めげずに探してみた所、こんなサイトがありました。

Linked Open Addresses Japan(試作版)
http://uedayou.net/loa/

Linked Open Addresses Japanは、日本の住所データをLinked Open Dataとして提供するWebサイトです。
本サイトは、Cross Origin Resource Sharing(CORS)にも対応しています。JavaScriptから直接住所データを取得できます。

すばらしい。これを使わせて貰おう。

例えばここですが、
http://uedayou.net/loa/東京都千代田区千代田1
JSONだとこんな感じになります。

{
    "http://uedayou.net/loa/東京都千代田区千代田1": {
        "http://imi.go.jp/ns/core/rdf#丁目": [
            {
                "type": "literal", 
                "value": "千代田"
            }
        ], 
        "http://imi.go.jp/ns/core/rdf#市区町村": [
            {
                "type": "literal", 
                "value": "千代田区"
            }
        ], 
        "http://imi.go.jp/ns/core/rdf#番地": [
            {
                "type": "literal", 
                "value": "1"
            }
        ], 
        "http://imi.go.jp/ns/core/rdf#都道府県": [
            {
                "type": "literal", 
                "value": "東京都"
            }
        ], 
        "http://purl.org/dc/terms/references": [
            {
                "type": "uri", 
                "value": "http://geonames.jp/resource/東京都千代田区千代田"
            }
        ], 
        "http://schema.org/image": [
            {
                "type": "uri", 
                "value": "http://uedayou.net/loa/東京都千代田区千代田1.jpg"
            }
        ], 
        "http://www.geonames.org/ontology#parentFeature": [
            {
                "type": "uri", 
                "value": "http://uedayou.net/loa/東京都千代田区千代田"
            }
        ], 
        "http://www.w3.org/1999/02/22-rdf-syntax-ns#type": [
            {
                "type": "uri", 
                "value": "http://imi.go.jp/ns/core/rdf#住所型"
            }
        ], 
        "http://www.w3.org/2000/01/rdf-schema#label": [
            {
                "type": "literal", 
                "value": "東京都千代田区千代田1"
            }
        ], 
        "http://www.w3.org/2003/01/geo/wgs84_pos#lat": [
            {
                "datatype": "http://www.w3.org/2001/XMLSchema#double", 
                "type": "literal", 
                "value": "35.68433"
            }
        ], 
        "http://www.w3.org/2003/01/geo/wgs84_pos#long": [
            {
                "datatype": "http://www.w3.org/2001/XMLSchema#double", 
                "type": "literal", 
                "value": "139.752391"
            }
        ]
    }
}

これを取って来て Vue.js のテンプレートに展開してみます。

JSON を Vue.js テンプレートに展開

スクリプト部分は以下の通り。

<script>
    axios.get('http://uedayou.net/loa/%E6%9D%B1%E4%BA%AC%E9%83%BD%E5%8D%83%E4%BB%A3%E7%94%B0%E5%8C%BA%E6%B0%B8%E7%94%B0%E7%94%BA%E4%B8%80%E4%B8%81%E7%9B%AE7.json')
      .then(function (response) {
        initVue(response.data);
      })
      .catch(function (error) {
        console.log(error);
      });

    function initVue(info){
        new Vue({
                el: '#app',
                data: {
                  infos: info["http://uedayou.net/loa/東京都千代田区永田町一丁目7"]
                }
            })
    }
</script>

axios の Ajaxレスポンスデータそのものは、response.data に入って来ます。
また、Ajaxリクエストと、Vue.js の new をそれぞれで書くと、Ajaxリクエストが完了するよりも先に
Vue.js の初期化が終わってしまうので、axios のコールバックに Vue.js の new を仕掛けました。

initVue に渡される info は、上記 Json そのものなので、”http://uedayou.net/loa/東京都千代田区千代田1″
の Value だけを Vue.js の data に infos の名前で渡しています。

これに対して、テンプレート部分は以下の通りです。

<table id="app">
  <tr>
    <td>項目</td>
    <td>データタイプ</td>
    <td>データ</td>
  </tr>
  <tr v-for="(value, key) in infos">
    <td>{{ key }}</td>
    <td>{{ value[0].type }}</td>
    <td>{{ value[0].value }}</td>
  </tr>
</table>

infos は Vue.js のテンプレート構文で使われていますが、結局は Javascript のオブジェクトなので
value[0].type みたいな指定の仕方ができるのですね。

これを実行すると、だいたいこんな感じになります。

項目 データタイプ データ
http://www.w3.org/1999/02/22-rdf-syntax-ns#type uri http://imi.go.jp/ns/core/rdf#住所型
http://www.w3.org/2000/01/rdf-schema#label literal 東京都千代田区永田町一丁目7
http://www.w3.org/2003/01/geo/wgs84_pos#lat literal 35.674487
http://www.w3.org/2003/01/geo/wgs84_pos#long literal 139.74708
http://purl.org/dc/terms/references uri http://geonames.jp/resource/東京都千代田区永田町一丁目
http://schema.org/image uri http://uedayou.net/loa/東京都千代田区永田町一丁目7.jpg
http://imi.go.jp/ns/core/rdf#都道府県 literal 東京都
http://imi.go.jp/ns/core/rdf#市区町村 literal 千代田区
http://imi.go.jp/ns/core/rdf#丁目 literal 永田町一丁目
http://imi.go.jp/ns/core/rdf#番地 literal 7
http://www.geonames.org/ontology#parentFeature uri http://uedayou.net/loa/東京都千代田区永田町一丁目

これらを一通りの htmlファイルにするとこんな感じ。シンプルですね。

<html>

<head>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>

<body>
<table id="app" style="display:none">
  <tr>
    <td>項目</td>
    <td>データタイプ</td>
    <td>データ</td>
  </tr>
  <tr v-for="(value, key) in infos">
    <td>{{ key }}</td>
    <td>{{ value[0].type }}</td>
    <td>{{ value[0].value }}</td>
  </tr>
</table>

<script>
    axios.get('http://uedayou.net/loa/%E6%9D%B1%E4%BA%AC%E9%83%BD%E5%8D%83%E4%BB%A3%E7%94%B0%E5%8C%BA%E6%B0%B8%E7%94%B0%E7%94%BA%E4%B8%80%E4%B8%81%E7%9B%AE7.json')
      .then(function (response) {
        initVue(response.data);
      })
      .catch(function (error) {
        console.log(error);
      });

    function initVue(info){
        new Vue({
                el: '#app',
                data: {
                  infos: info["http://uedayou.net/loa/東京都千代田区永田町一丁目7"]
                },
                mounted: function(){
                  document.getElementById("app").style.display = "";
                }
            })
    }
</script>

</body>
</html>

テンプレートに {{ key }} と書くと、一瞬括弧が表示されてしまうので最初はテーブルそのものを display:none にして、
Vue.js の mounted で表示するようにしています。まあ、v-bind を使えばそもそもテンプレートに {{ hoge }} と
書かなくて良かったような気がするけれどそれはまた今度で。

コメントを残す

メールアドレスが公開されることはありません。