スタッフブログ Staff Blog

Vue.jsに触れてみて

半年程前から『Vue.js(ビュージェイエス)』を扱うようになりました。Vueは、公式サイトでは「ユーザーインターフェイスを構築するためのプログレッシブフレームワーク」と紹介されています。リアクティブなデータバインディングとコンポーネントシステム等が特徴と言われますが、その辺りは「はじめに - Vue.js」から順にお読み頂いた方が理解しやすいでしょう。

本記事では、私がVueを触って感じたメリットなどをいくつかご紹介したいと思います。

低い学習コスト

以前Angularを使用してアプリケーションを組んだことがありますが、機能が多く学習に時間がかかりそうだなという印象を持ちました。しかし、Vueは数時間手を動かしながら学習することでコアな機能は習得できるかと思います。株式会社ピクセルグリッドさまが毎週配信されている『CodeGrid』でもちょうど初心者向けの連載が始まっていたところで、私はそれを読みながら学習を進め、あっという間に一つのアプリケーションを作成することができました。

現在は公式ドキュメント(日本語版)を読み、記事にはなかった情報などを習得しています。公式ドキュメントも親しみやすく、Vueの知識を付けるには最適でしょう。

見通しの良いコードの実現

Movable Typeを使用して何かの情報...例えば病院のリストや金融機関のリスト、ニュースなどの記事をJSONやXMLで出力し、一覧表示するケースはよくあるのではないかと思います。Vueではテンプレートとロジックを容易に分離でき、見通しの良いコードに仕上げることができます。

例えば、最近私が見たとあるサイトでは次のようにしてXMLを読み込みHTMLを組み立てていました。
(元のコードは実行速度に難があったため、チューニングしたものを掲載します。)

$.ajax({
  url: "news.xml",
  dataType: "xml",
  success: function(xml) {
    var ul = document.createElement('ul');
    var lists = [];
    var items = xml.getElementsByTagName('item');

    for (var i = 0, nItems = items.length; i < nItems; i += 1) {
        var date = items[i].getElementsByTagName('entryDate')[0].textContent;
        var text = items[i].getElementsByTagName('entryTitle')[0].textContent;
        var html = '<li class="item"><a href="#" data-itemindex="' + i + '">' +
                    '<span class="date">' + date + '</span><span class="title">' +
                    text + '</a></li>';
        lists.push(html);
    }

    ul.innerHTML = lists.join('');
  }
});

Vueを使うと、以下のようにテンプレートとXMLを読み込むロジックを分離することができます。(ここでは.vue拡張子の単一ファイルコンポーネントの仕組みを利用しています。)記事データをdataオブジェクトのentriesプロパティ入れるとビューの更新が行われ、即座に記事リストが表示されます。

<template>
  <ul>
    <li v-for="entry of entries" :key="entry.id" class="item">
      <a href="#"><span class="date">{{entry.date}}</span><span class="title">{{entry.title}}</span></a>
    </li>
  </ul>
</template>

<script>
export default {
  data () {
    return {
      entries: []
    }
  },
  created () {
    $.ajax({
      url: 'news.xml',
      dataType: 'xml'
    }).done((xml) => {
      const items = xml.getElementsByTagName('item');
      let entries = [];

      for (let i = 0, nItems = items.length; i < nItems; i += 1) {
        const id = items[i].getElementsByTagName('entryID')[0].textContent;
        const title = items[i].getElementsByTagName('entryTitle')[0].textContent;
        const date = items[i].getElementsByTagName('entryDate')[0].textContent;
        entries.push({
          index: i,
          id: id,
          title: title,
          date: date
        });
      }

      this.entries = entries;
    });
  },
};
</script>

アプリケーションにはリスト表示以外のUIやメソッドも必要でしょうから、どちらがコードを記述しやすいか、またどちらがメンテナンスしやすいか、は自ずと分かるのではないかと思います。

リアクティブシステムでロジックの複雑さを回避

記事一覧にページネーションを実装する例について考えてみましょう。

まず、dataオブジェクトへ現在のページ・1ページの表示記事数・最大ページを追加します。そして「次のページへ」「前のページへ」がクリックされた時は、dataオブジェクトの現在のページ数のみ変更します。現在のページ数が変更されると自動的にdispEntriesメソッドが呼ばれ、指定したページを表示するために必要な記事を抜き出してビューに反映できるようになりました。

ボタンをクリックした時のメソッド内でビューを更新するメソッドを呼ぶ必要がないため、メソッドの呼び出しがあちこちに点在し蜘蛛の巣のように絡み合うような事態を避けることができるのが大きなメリットではないかと感じました。

<template>
  <div id="news">
    <ul>
      <li v-for="entry of dispEntries" :key="entry.id" class="item">
        <a href="#"><span class="date">{{entry.date}}</span><span class="title">{{entry.title}}</span></a>
      </li>
    </ul>
    <button @click="loadPrevPage" v-if="page !== 0">前のページ</button>
    <button @click="loadNextPage" v-if="page !== maxPages">次のページ</button>
  </div><!-- /#news -->
</template>

<script>
export default {
  data () {
    return {
      page: 0,
      nPages: null,
      itemsPerPage: 8,
      maxPages: 50,
      entries: []
    }
  },
  created () {
    // 「見通しの良いコードの実現」で紹介したコード
  },
   methods: {
    loadPrevPage () {
      this.page -= 1;
    },
    loadNextPage () {
      this.page += 1;
    }
  },
  computed: {
    dispEntries () {
      var startItemIndex = this.page * this.itemsPerPage
      return this.entries.slice(startItemIndex, startItemIndex + this.itemsPerPage)
    }
  }
}
</script>

また、現在表示されているページに応じて「前のページ」を消すことも容易です。button要素にv-if="page !== 0"としておけば、dataオブジェクトの現在のページ数が0になった時、ボタンは自動的に非表示になります。

vue-webpack-boilerplateで開発が便利に

vue-cli」を使用することで、Vueを使用したプロジェクトに必要な各種ファイルが用意され、スピーディーに制作を開始することができました。

プロジェクトのテンプレートはいくつかあるようですが、私は公式に配布されている「vue-webpack-boilerplate」を利用しました。(コマンドラインでvue init webpackを実行するとダウンロードされます。)

vue-webpack-boilerplateを利用して大変便利だったのは、画面の差分更新(Hot Reloading)を実現する「webpack-hot-middleware」が組み込まれていた点です。例えば何かのリストをフィルタ表示している時のビューを作成する場合、Vueのテンプレートを編集して画面が自動リロードされるとまた一から条件を設定してフィルタをしなければなりません。しかし、vue-webpack-boilerplateを利用していれば変更があったところのみを上手く画面に反映してくれるので、一から条件を設定しなおす必要がありませんでした。この差分更新(Hot Reloading)は、開発の大きな助けになるのではないかと感じました。

お問い合わせ Contact

制作のご依頼、ご相談などは下記のフォームからご連絡ください。