Vue.jsは、Angular、Reactと並んで人気のモダンなJavaScriptフレームワークです。
拙著「いちばんやさしい Vue.js 入門教室」(ソーテック社)では、Vue.jsを使用して「Youtube検索プログラム」を作成しています。

まずCDNでVue.jsのフレームワークをリンクすることにより、Youtube検索プログラムを作成しています。続いてnode.jsベースのVue CLI 3を使用して、シングルファイルコンポーネントとしてYoutube検索プログラムを作成しています。

Vue.jsの基本的な使用法については書籍を参照していただくことにして、ここではその概要を紹介します。

Vue.js以外に、HTTP通信ライブラリ「axio」と、CSSフレームワーク「Bootstrap」を使用しています。

作成するYouTube動画検索アプリについて

Web APIとは、Webサーバ上で提供されるさまざまなサービスを、クライアント側のプログラムからアクセスするための仕組みのことです。現在ではさまざまなサイトが検索サービスなどをWeb APIとして提供しています。
次に、YouTubeの提供する「YouTube Data API v3」を使用して、次のようなYouTube動画検索プログラムを作成します。
テキストボックスに検索文字列を入力して「検索」ボタンをクリックすると、検索結果がHTMLの表に一覧表示されます。
●GitHub Webのサンプル
・実行画面
テキストボックスにキーワードを入力して「検索」ボタンをクリック
検索結果のサムネール部分をクリックすると、YouTubeのWebサイトにジャンプし動画を再生できます。

APIキーを取得する

YouTubeの動画検索を行うには、「YouTube Data API v3」のAPIキーが必要です。また、APIキーを取得するにはGoogleアカウントが必要になります。
1. Webブラウザで、GoogleアカウントでログインしGoogle Developers Console(https://console.developers.google.com/apis/library)を開きます。
2. 「YouTube Data API v3」ページを開き「有効にする」ボタンをクリックします。
3. 「ライブラリ」ページで「作成」ボタンをクリックしてプロジェクトを作成します。
4. 「認証情報」ページで情報を設定し「必要な認証情報」ボタンをクリックします。
5. APIキーが表示されます。

axiosライブラリについて

Ajaxは「Asynchronous JavaScript + XML」の略で、Webブラウザ上で動作するJavaScriptプログラムにより、Webサーバから非同期通信(Asynchronous)でXMLデータを取得し、取得したデータをWebコンテンツに動的に反映するという手法です。現在ではデータ形式として、XMLよりも軽量でシンプルなJSON形式が使用されることが多くなって来ています。
Vue.js自体には、Ajax通信機能は用意されていないため、JavaScriptで直接XMLHttpRequestsオブジェクトをコントロールするか、外部のライブラリを使用する必要があります。ここではVue.jsの公式ドキュメントで紹介されているaxios(アクシオス)というAjax通信ライブラリを使用する方法を紹介します。axiosはPromiseという非同期処理機能をベースにしたライブラリです。

axiosライブラリを使用するために

axiosをCDN経由で読み込むには、HTMLファイルに次のようなscript要素を記述します。
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

axiosの基本的な使い方

axiosを使用して、WebサーバにHTTPプロトコルのgetリクエストを送信し、レスポンスを受け取るには次のようにします。
axios
    .get("URL") // (1)
    .then(function(res){    // (2)
        // レスポンスを処理
    }
    .catch(function(err) {  // (3)
        // エラーが起こった場合の処理を記述
    });
(1)のget()メソッドは、引数で指定したアドレスにHTTPプロトコルのgetリクエストを送信します。結果が正常に受け取れれば、(2)のthen()メソッドの引数で指定した関数で処理を行います。関数では引数resにレスポンスが渡されます。
なお、エラーが発生した場合の処理を記述したい場合には、さらに(3)でcatch()メソッドを接続します。

■ CDNバージョンのYoutube検索プログラム

CDNヴァージョンのソースは以下のGitHubリポジトリからダウンロードできます。

プログラム部分

次に、プログラム部分のリストを示します。
リスト: youtube1.js
var vm = new Vue({
    el: '#app',
    data: {
        results: null,  // (1)
        keyword: '',    // (2)
        params: {   // (3)    
            q: '',  // 検索文字列
            part: 'snippet',
            type: 'video',
            maxResults: '10', // 最大検索数 // (4)
            // キーを設定
            key: 'APIキーを設定'   // (5)
        }
    },
    methods: {
        searchMovies: function() {   // (6)
            this.params.q = this.keyword;   // (7)
            var self = this;
            axios
                .get('https://www.googleapis.com/youtube/v3/search', {params: this.params}) // (8)
                .then(function(res) {
                    self.results = res.data.items;  // (9)
                })
                .catch(function(err) {
                    console.log(err);
                });
        }
    }
});
データオブジェクトとして、(1)で検索結果を格納するresultsプロパティ、(2)で検索キーワードを格納するkeywordプロパティを用意しています。(3)のparmsにはクエリパラメータを格納しています。(4)のmaxResultsは最大検索数です。自由に設定して構いません。(5)のkeyでは取得したAPIキーを設定します。
(6)が検索を実行するsearchMovies()関数です。(7)でクエリパラメータの「q」に検索文字列を代入しています。
(8)axiosのget()メソッドでは、YouTube Data APIのURLにクエリパラメータを加えて実行しています。
.get(‘https://www.googleapis.com/youtube/v3/search’, {params: this.params})
クエリパラメータ
then()メソッドでは、(9)で検索結果として取得したitems配列をresultsプロパティに代入しています。これでresults配列の各要素にはそれぞれの動画の情報が格納されます。

HTMLテンプレート

次にHTMLテンプレート部分のリストを示します。
リスト: youtube1.html
    <div id="app">
            <input v-model="keyword" placeholder="検索キーワードを入力" />  // (1)
            <button @click="searchMovies">検索</button>  // (2)
            <table class="table" v-show="results">
                <tr>
                    <th>#</th>
                    <th>ムービー</th>
                    <th>情報</th>
                </tr>
                <tr v-for="(movie, index) in results" v-bind:key="movie.id.videoId">  // (3)
                    <td>{{ index + 1 }}</td>
                    <td>
                        <a  // (4) 
                            v-bind:href="'https://www.youtube.com/watch?v=' + movie.id.videoId"
                            ><img width=320 height=180
                                v-bind:src="movie.snippet.thumbnails.medium.url"
                        /></a>
                    </td>
                    <td>
                        <b>{{ movie.snippet.title }}</b> <br /> // (5)
                        <span class="desc">{{
                            movie.snippet.description
                        }}</span>
                    </td>
                </tr>
            </table>
        </div>
(1)で、検索文字列入力用のテキストボックスを用意し、v-modelディレクティブでkeywordプロパティとバインドしています。
(2)では「検索」ボタンがクリックされたらsearchMovies()メソッドを呼び出すようにしています。
検索結果の一覧を表示する表(table要素)では、(3)でv-forディレクティブには動画を一つずつ取り出し変数movieに格納しています。key属性には、ビデオのIDをバインドしています。
(4)では、img要素にv-bindディレクティブでsrc属性をバインドすることにより、動画のサムネールを表示しています。またa要素のhref属性にYouTubeの動画のURLをバインドすることにより、サムネールがクリックしたら動画サイトにジャンプするようにしています。
(5)では、動画のタイトル(title)と、情報(description)を表示しています。

■ シングルファイルコンポーネント・バージョンのYoutube検索プログラム

続いて、Vue CLI 3を使用したシングルファイルコンポーネント・バージョンのYoutube検索プログラムを示します
ソースは次のGitHubリポジトリからダウンロードできます。

シングルファイルコンポーネントとは

シングルファイルコンポーネントは、Vue.jsのコンポーネントを構成する、HTMLテンプレート、JavaScript、スタイルシートを一つのファイルにまとめたものです。拡張子は「.vue」になります。
次に、シンプルなシングルファイルコンポーネントの例を示します。

リスト: hello.vue

<template>  //←(1)
  <div>
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {    //←(2)
  name: "Hello",
  props: {
    msg: String
  }
};
</script>

<style scoped>  //←(3)
h1 {
  color: red;
}
</style>

(1)のように、HTMLテンプレートはtemplate要素として記述します。(2)のようにコンポーネントのインスタンスは、ES2015のexport default文でエクスポートします。(3)のようにスタイルシートのstyle要素も同じファイルに記述できます。

モジュールを追加する

YouTube動画検索アプリでは、外部ライブラリとしてaxiosとBootstrapを使用しています。これらをVue CLI 3で開発を行う場合には、npmを使用してnode.jsのモジュールとしてインストールできます。
コマンドラインでプロジェクトのディレクトリに移動し、次のように「npm install」コマンドを実行して2つのモジュールをインストールします。

npm install bootstrap【Enter】
npm install axios【Enter】

SearchYoutubeコンポーネントの作成

次に、SearchYoutubeコンポーネントとしてい使用するシングルファイルコンポーネントのファイル「SearchYoutube.vue」を示します。

リスト: SearchYoutube.vue

<template>  //←(1)
  <div class="hello">
    <h1>{{ msg }}</h1>  //←(2)
    <input v-model="keyword" placeholder="検索キーワードを入力">
    <button @click="searchMovies">検索</button>

    <table class="table" v-show="results">
      <tr>
        <th>#</th>
        <th>ムービー</th>
        <th>情報</th>
      </tr>
      <tr v-for="(movie, index) in results" v-bind:key="movie.id.videoId">
        <td>{{ index + 1 }}</td>
        <td>
          <a v-bind:href="'https://www.youtube.com/watch?v=' + movie.id.videoId">
            <img width="320" height="180" v-bind:src="movie.snippet.thumbnails.medium.url">
          </a>
        </td>
        <td>
          <b>{{ movie.snippet.title }}</b>
          <br>
          <span class="desc">
            {{
            movie.snippet.description
            }}
          </span>
        </td>
      </tr>
    </table>
  </div>
</template>

<script>
import axios from 'axios';  //←(3)
import 'bootstrap/dist/css/bootstrap.min.css';  //←(4)

export default {    //←(5)
  name: "SearchYoutube",
  data: function() {    //←(6)
    return {
      results: null,
      keyword: "Giulietta Machine",
      params: {
        q: "", // 検索文字列
        part: "snippet",
        type: "video",
        maxResults: "10", // 最大検索数
        key: "APIキーを設定"
      }
    };
  },
  props: {  //←(7)
    msg: String
  },
  methods: {
    searchMovies: function() {
      this.params.q = this.keyword;
      var self = this;
      axios //←(8)
        .get("https://www.googleapis.com/youtube/v3/search", {
          params: this.params
        })
        .then(function(res) {
          self.results = res.data.items;
        })
    }
  }
};
</script>

<style scoped>  //←(8)
.desc {
  color: gray;
}
</style>

HTMLテンプレートは、(1)のtemplate要素として記述しています。内容は(2)でmsgプロパティを表示している以外は以前のものと同じです。
script要素では、(3)(4)でaxiosとbootstrapのCSS部分を読み込んでいます。(5)の「export default」でコンポーネントのインスタンスを定義しています。コンポーネント化したことで、(6)のdataは関数の戻り値としている点に注意してください。
また、新たに(7)のpropsで、タイトルとして表示するテキストであるmsgプロパティを登録しています。
(8)のaxiosを使用して検索結果をresultsプロパティに格納しています。なお、ESLintの初期設定ではconsole.log()メソッドがあるとエラーが表示されるため、ここではcatch()メソッドによるエラー処理を省略しています。
(9)でスタイルシートを記述しています。
シングルファイルコンポーネント化するといっても、以外と変更点は少ないと思います。しかも、Visual Studio CodeのようなエディタではHTMLテンプレート部分が色分けされてわかりやすく表示されます。

App.vue

次に、メインのシングルファイルコンポーネントであるApp.vueを変更し、SearchYoutubeコンポーネントを読み込むようにします。

リスト: App.vue

<template>
  <div id="app">
    <SearchYoutube msg="YouTube動画検索"/>  //←(1)
  </div>
</template>

<script>
import SearchYoutube from './components/SearchYoutube.vue'  //←(2)
export default {
  name: 'app',
  components: {
    SearchYoutube   //←(3)
  }
}
</script>

template要素では(1)でSearchYoutubeコンポーネントを使用して、msg属性にタイトルとして”YouTube動画検索”を渡しています。script要素では、(2)のimport文でSearchYoutube.vueを読み込んで、(3)でコンポーネントとして登録しています。

その他のサンプル

本書のその他のサンプル

  • おみくじアプリ
  • カウント
  • お絵かきアプリ
  • ローカルストレージに保存可能なtodoリスト
  • スタイドショー
  • 書籍リストのJSONデータを読み込む
  • アニメーション
  • etc.

大津真