jQuery
vue.js
serverless

サーバレスアプリ開発をjQueryでがんばらないためのVue.js

サーバレス構成のWebアプリ開発を担当し、そこでVue.jsを使ってみたので採用した経緯と、Vue.jsの何を使ったかを紹介する。

これまでのWebアプリ開発

JavaのWebアプリ開発ならThymeleafやFreemarkerなどのテンプレートエンジンを使用していた。
サーバレスだと、HTMLとJavaScriptで表示の処理を行うため、JavaScriptの処理が増える。
よく使われるのはjQueryによってDOMを操作し、HTMLを動的に変更する方法だろう。

jQueryのDOM操作は辛いよ

jQueryを使ったことがあればお分かりだと思うが、jQueryによるDOM操作は「このイベントで、このvalueがxxxなら、このDOMを変更する」という手続き型のコードになる。
JavaScriptの処理が増えると、この手続き型のコードが増えてデータと状態の管理が煩雑になる。
また、JavaScript側に表示の処理があるためHTMLを簡単に変更できない。

そこでVue.jsですよ

SPAっぽい要件なので、SPAに適したJavaScriptフレームワークを使う方がよさそう。
SPAがやりたいわけではないが。

Vue.jsは社内で検証の候補になっていたので採用してみた。
公式ガイドをさらっと読むと、HTMLに値を埋め込める、条件分岐、ループを組み込めるので、テンプレートエンジンと同じことができそう。
クライアントの開発は一任されていたので、試しやすかったのもある。

Vue.jsのはじめかた

お手軽にはじめるなら script タグに1行追加するだけ。

HTML
<!-- 開発バージョン(警告出力とデバッグモードあり) -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
HTML
<!-- 本番バージョン(警告出力なし、圧縮済み -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>

但し、webpackでビルドが必要な機能は使えない。例えば単一ファイルコンポーネント。
単一ファイルコンポーネントはHTMLを構成するヘッダ、ボディなどを部品ごとに分けて扱える。
便利ではあるが、Node.jsのツール(npm, webpack, vue-cli)が必要になる。
公式ガイドでは、最初は script から使用することをおすすめしている。
機能数も少ないので script から使用する。

Vueのアプリ開発

Vueインスタンスの作成

画面ごとにHTMLを分けたので、HTMLごとにルートVueインスタンスを生成。
Vueインスタンスで使用するオプションは el, data, methods, computed のみ。

JavaScript
var vm = new Vue({
  el: '#app',
  data: {
    items: [
      {
        isbn: '4873118069',
        title: 'サーバーレスシングルページアプリケーション',
        publisher: 'オライリージャパン',
        price: 2808
      },
      {
        isbn: '4798155160',
        title: 'AWSによるサーバーレスアーキテクチャ',
        publisher: '翔泳社',
        price: 3888
      }
    ]
  },
  methods: {
    // メソッド
  },
  computed: {
    // 算出プロパティ
  }
})
el
Vueインスタンスの対象となるHTML要素を指定する。
data
バインドする変数を格納する。変数の値が変更されるとHTMLに反映される。
methods
v-on で呼び出す関数を記述する。
computed
算出プロパティ。依存するものが更新されなければ以前計算された結果を返す。

HTMLにJavaScriptの値を埋め込む

Vueインスタンスの data の変数を {{変数}} のように2重の中括弧で囲むとHTMLに値が埋め込める。
変数を処理させて表示する場合は算出プロパティを使用する。

例えば、合計金額を算出して表示するには以下のように記述する。

JavaScript
var vm = new Vue({
  el: '#app',
  data: {
    items: [
      {
        isbn: '4873118069',
        title: 'サーバーレスシングルページアプリケーション',
        publisher: 'オライリージャパン',
        price: 2808
      },
      {
        isbn: '4798155160',
        title: 'AWSによるサーバーレスアーキテクチャ',
        publisher: '翔泳社',
        price: 3888
      }
    ]
  },
  methods: {
    // メソッド
  },
  computed: {
    priceTotal: function() {
      var total = 0;
      for (var item in items) {
        total += item.price;
      }
      return priceTotal;
    }
  }
})
HTML
合計金額:{{priceTotal}}

ディレクティブの使い方

Vue.jsはHTMLタグの中にディレクティブという特別な属性を埋め込むことでHTMLを制御する。
使用したディレクティブは以下の通り。

v-if

条件で表示を切り替えるのに使用する。

v-show も同じ用途で使用されますが、v-show はCSSの display: none で表示を隠すのと同じでDOMは消えない。
DOMの追加、削除がない分、描画は v-show の方が早い。

例えばログインユーザの権限で表示項目を変える場合はDOMに出したくないから v-if の方がよさそう。
プルダウンやラジオボタンで項目を切り替えるのであれば、v-show の方がよさそう。

v-for

data の配列データを1件ずつループで処理するのに使用する。
例えばAjaxでDBから取得したデータを一覧表示する場合に使用される。
一覧を10件ずつ表示する場合は算出プロパティを使用するとよさそう。

JavaScript
var vm = new Vue({
  el: '#app',
  data: {
    items: [], // AjaxでDBから取得
    pagination: {
      page: 0,
      pageSize: 10,
    },
    startPage: 0,
    pageSize: 10,
  },
  methods: {
    // メソッド
  },
  computed: {
    pageItems: function () {
      var startPage = this.pagination.page * this.pagination.pageSize;
      return this.items.slice(startPage, startPage + this.pagination.pageSize);
    },
  }
})
HTML
<table>
  <thead>
    <tr>
      <th>ISBN</th>
      <th>タイトル</th>
      <th>出版社</th>
      <th>値段</th>
    </tr>
  </thead>
  <tbody>
    <tr v-for="item in pageItems">
      <td>{{item.isbn}}</td>
      <td>{{item.title}}</td>
      <td>{{item.publisher}}</td>
      <td>{{item.price}}</td>
    </tr>
  </tbody>
</table>

v-bind

タグの属性に値を埋め込むのに使用する。
例えば class の属性を動的に切り替えるには <div v-bind:class="disabled: isDisabled"></div>のように記述すると dataisDisabled がtrueの場合に disabled が埋め込まれる。
v-bind:class:class のように省略して記述することもできる。

また、v-for と組み合わせて動的にセレクトボックスを作ることができる。

HTML
<select>
  <option v-for="item in items" :value="item.isbn">{{item.title}}</option>
</select>

v-on

イベントで methods に記述した関数を呼び出すのに使用する。
例えばボタンクリック時のイベントは v-on:click="ファンクション名" のように記述する。
また、@click="ファンクション名" のように省略して記述することもできる。

v-model

input, select, textarea の値を data の変数にバインドするのに使用する。

v-cloak

v-cloak を使うことで、値が埋め込まれるまで {{変数}} がそのまま表示されるのを防ぐことができる。
CSSで display: none を適用しておきます。

CSS
[v-cloak] {
  display: none;
}

まとめ

サーバレス構成だとJavaScriptフレームワークは必須かなと思う。
ReactやAngularは分からないが、Vue.jsは使いやすい。
何よりDOM操作から開放されることがよい。