Webとデザインのあれこれ

プログラミングとUIデザインの学習記録です。

フロントエンド開発(Vue.js)入門

Vue.jsを使って簡単なアプリを作ってみよう

こちらの記事の目的

現在、私はフィヨルドブートキャンプというプログラミングスクールに在籍しております。Ruby on Railsを扱っており、主にバックエンド開発の学習を対象としていますが、フロントエンド開発のカリキュラムの一環としてVue.jsでTodoアプリを作成するという課題が出されました。こちらはその課題の備忘録となります。

Vue.jsとは何か

フロントエンドの開発に用いられる人気のJavaScriptフレームワークです。その他、代表的なものとしてFacebook社製のReact、Google社が開発したAngularなどが存在します。フレームワーク間の比較等はこの記事では扱いません。

モダンフロントエンドにおけるJSフレームワークの特徴

フレームワークの種類を問わず、現在主流のJSフレームワークの特徴は以下の2つのキーワードで説明できます。

  •  リアクティブ
    • JavaScript側のデータの更新がWebページのDOMツリーに即座に反映される仕組みのこと
    • JavaScript側のVueインスタンス内のデータとHTMLを基本としたテンプレート構文に記述した値がバインドされ、データを更新すると、それがすぐにDOMツリーに反映されてWebブラウザの画面が更新される
    • DOMとは
      • JavaScriptからHTML文書やXML文書の要素を操作する仕組み
      • HTML要素をツリー構造として扱うことが可能で、そのツリー構造をDOMツリー、DOMツリーを構成する要素をノードと呼ぶ
  • コンポーネントによる開発
    • Webサイトの構成要素を複数のパーツに分割して開発するという手法
    • コンポーネントを再利用することで効率的に開発が可能

Vue.jsの特徴

Reactなど他のフレームワークを利用したことがないため、難易度などについてはよくわからないのですが、以下のような特徴が挙げられています。

  • ユーザーインターフェースを作るライブラリであること
  • 利用にあたって、ES6によるプログラミングを強制しないこと
  • 初期段階ではNode.js、WebpackやBabelなど初心者にハードルの高い開発ツールの知識が必ずしも必要ないこと
    • Node.jsやVue CLI 3、またVue RouterやVuexなどのライブラリと連携してSPA(シングル・ページ・アプリケーション)の開発がもちろん可能であること
    • 必要に応じて拡張可能なプログレッシブ・フレームワークであること(小さく初めて、少しずつ進められる)
  • HTML, CSS, JavaScriptの知識があれば始められるなど、ReactやAngularなどと比較して学習コストが低いこと

そして何よりも、単一ファイルコンポーネントの利用こそVue.jsの最大の特徴と言われています。

Vue.jsではNode.jsやVue CLI 3といった開発環境を導入することにより、単一ファイルコンポーネントと呼ばれるHTML、CSS、JSを1つのファイルにパッケージングしたより柔軟なコンポーネントが利用可能となります。

ただ、単一ファイルコンポーネントの拡張子が.vueのファイルであること、かつES6のモジュール機能を利用しているため、利用するにはNode.jsベースのモジュールハンドラやトランスパイラなどのツールが必要となります。

f:id:b_leiu:20190824170333p:plain:w300

また、公式ガイドが非常に充実していることも利用するメリットの一つです。日本語で記載されたわかりやすいガイドがあると心強いですよね!

jp.vuejs.org

Udemyの日本語動画や関連書籍もどんどん増えてきているので、お薦めです。

Todoアプリ作成に入ろう!

それでは、早速内容に入ります。Todoアプリ作成にはデータバインディングとディレクティブの知識が必須となります。 まず、その前にインストール方法について確認しましょう。

インストール方法

Vue.jsを利用するには、以下の3種類の方法が存在します。

  1. CDN(Content Delivery Network)
  2. NPM
  3. CLI

CDNとはWebコンテンツのデリバリーに最適化したネットワークのことです。手軽に利用するにはCDNからVue.jsを読み込むのが最適ですので、こちらの内容で進めます。

また、公式ガイドでは大規模アプリケーションを構築する際にはNPM、大規模なSPA開発にはCLIの利用を推奨しています。それぞれ内容を確認してみて下さい。

CDNによるインストールは驚くほど簡単です。公式ガイドから、以下の内容を抜き出してHTMLのbodyタグの最後に貼るだけです。

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>

@2.6.0は最新のバージョン番号のことです。これでVue.jsが使えますね!

データバインディングの基本的な仕組み

記事の前半でリアクティブという言葉に触れました。JavaScript側のデータの更新がDOMツリーに即座に反映される仕組みのことです。 DOMの文書ツリーとJavaScriptのオブジェクトの仲介をするのがJavaScriptフレームワークの役割です。

Vue.jsの場合、Vueインスタンス内のデータとHTMLを基本としたテンプレート構文に記述した値が結び付けられます。 データが変更されても、それがすぐにDOMツリーに反映されるため、ブラウザ上での表示も更新されます。 具体例を見ていきましょう。

# JavaScript(Vueインスタンス)
var app  = new Vue({
  # オプション指定
  el: '#app',
  data: {
     message: "Hello!!!"
  }
})

Vueインスタンスの生成にはnew演算子とVueコンストラクタを使用します。引数はオブジェクトリテラル({キー:値})です。

代表的なオプションは、以下の2つです。

  1. el(elementの略ですね)
  2. data

elではVueインスタンスに対応するHTML要素のid属性を指定します。上記の例の場合、idはappです。 dataはVueインスタンスの管理するデータオブジェクトのことです。

# HTMLテンプレート
<div id="app">
  <p>{{message}}</p>
</div>

こちらはHTMLテンプレートです。divタグ内でidが確認できますね。

ただ、見慣れない記号{{}}がありますね。これをMustache構文と呼びます。 この構文が、Vueインスタンスのデータオブジェクト内のmessage変数をバインドしてブラウザに表示します。 ブラウザで確認するとHello!!!と表示されるはずです。

ディレクティブ

データバインディングの基本を確認したので、ディレクティブの内容に入ります。 ディレクティブとはHTMLのタグ内に記述する「v-」で始まる属性のことです。

# HTML
<div id="app">
  <p><a v-bind:href="toMyBlog">常に初心者</a></p>
</div>

# JavaScript
var app = new Vue({
  el: '#app',
  data: {
    toMyBlog: 'https://tkm2.hatenablog.com/'
  }
})

上記の場合、HTML属性であるhref属性にリンク先のデータをバインドしています。HTMLの属性にMastache構文は利用できないためです。 因みに、v-bindの部分を省略して、:href=から記載しても構いません。省略記法ですね。

主要ディレクティブ

  • v-bind
    • HTML属性のバインド
  • v-for
    • 繰り返し処理
  • v-if(v-show)
    • 条件分岐
  • v-on
    • DOMのイベント処理
  • v-model
v-forによる繰り返し処理
# HTML
<div id="app">
  <ul>
    <li v-for="city in cities">{{city}}</li>
  </ul>
</div>

# JavaScript
new Vue({
 el: '#app',
 data: {
  cities: ['東京', '大阪', '名古屋']
 }
});

上記の場合、データオブジェクトのcitiesプロパティに配列を渡し、繰り返し処理を行うことでリストを表示しています。 変数 in 配列名という指定の他、(変数, index) in 配列名などインデックスを表示することも可能です。

f:id:b_leiu:20190824190245p:plain:w200

v-if/v-showによる条件分岐

v-if="値"の場合、値がtrueの場合などに要素が表示されます。プロパティの値に応じて、要素の表示/非表示を切り替える場合などに用います。

v-ifディレクティブはDOMから要素自体を削除するため、負荷が高くなります。表示/非表示を頻繁に繰り返す場合は、v-showを用いた方が無難です。

v-onによるDOMイベント処理
# HTML
<button v-on:click="add(index)" >
  Delete
</button>

# JavaScript
methods: {
        add: function(index) {
             # 処理内容は省略
            }
        }
    }

上記の例ではv-onというディレクティブを使用してDOMイベントの処理を記述しています。

Deleteボタンをクリックするとadd(index)メソッドが発動します(メソッドはVueインスタンス内で定義しています)。コロン(:)の後にDOMのイベント(click)を記述して、メソッドで処理を指定するという訳です。

v-onもv-bindと同様に省略記法が存在します。v-on:を省略して、頭に@をつけた@clickでOKです。

v-modelによる双方向データバインディング

v-modelはとても面白いディレクティブです。

# HTML
<div id="app">
<label for="pets">ペットはいますか?</label>
  <input id="pets" type="checkbox" v-model="pets" />
  {{pets}}
</div>

# JavaScript
new Vue({
 el: '#app',
 data: {
  pets: false
 }
});

petsプロパティがデフォルトでfalseになっています。チェックボックスにチェックを入れると、falseからtrueに変化するのです。

f:id:b_leiu:20190824201303p:plain:w200

f:id:b_leiu:20190824201209p:plain:w300

また、フォームのテキストボックスに文字列を入力すると、インスタンス内のプロパティがバインドされて双方向に値が変化します。

ディレクティブがどう作用するか実際に見てみよう!

<div id="app">
      # 省略
      <input
        type="text"
        v-model="newtask"
      />
      <button class="add" @click="addTask">追加</button>
      <ul>
        <li
          v-for="(todo, index) in todos"
        >
         # 省略
        </li>
      </ul>
      <pre>{{this.todos}}</pre>
      <pre>{{newtask}}</pre>
    </div>

# JavaScript
var app = new Vue({
    el: '#app',
    data: {
        newtask: '',
        todos: []
    },
    methods: {
        addTask: function() {
            if (this.newtask == '') return;
            this.todos.push({ text: this.newtask, done: false, hover: false}); 
            this.newtask = '';
        }
   # 省略

課題のため、全てのコードを記述することはできないですが、ディレクティブがどのように作用しているか確認を行います。

preタグの部分にthis.todosnewtaskを記述しています。追加ボタンをクリックした後に空配列のtodosがどうなるか、またnewtaskというプロパティがどう変化するか確認しましょう。

テキストエリアに「猫とお散歩」を入力すると(まだボタンはクリックしてません!)・・・

f:id:b_leiu:20190824211604p:plain:w400

プロパティも猫とお散歩に変化していますね!では、ボタンを押すと・・・

f:id:b_leiu:20190824211630p:plain:w400

空配列のtodosにオブジェクトがpushされ、リスト表示されていることがわかりますね。また、this.newtask=''により、入力した文字列はクリアされています。

v-modelやv-onが正しく作用しています。

このように複数のディレクティブを組み合わせて、Todoリストを作成します。その他にも以下の内容の機能を追加しました。

  • チェックボックスにv-modelを使用して、CSSプロパティの適用
  • v-showの条件分岐を利用して、削除ボタンの表示切り替え

ローカルストレージの利用と監視プロパティについて

実装はまだ終わりません。現時点ではリロードした場合、データは消えてしまいます。 DBを使用せずにデータをブラウザに保存してあげましょう。

ブラウザ側でデータをローカルディスクに保存するWebストレージ機能の出番です!HTML5より追加された機能ですね。

qiita.com

Webストレージは以下の2種類に分かれます。

  1. ローカルストレージ
  2. セッションストレージ

セッションストレージはセッション単位でデータを保存するため、ブラウザを閉じるとデータが消去されます。

ローカルストレージの場合は、データを永続的にクライアント(Webブラウザ)に保存することが可能です。

ローカルストレージについて

  • データをキーと値のペアで保存する
  • 文字列の形式でデータを保存する

ローカルストレージにデータを保存する場合は、setItem(キー、値)メソッドを使用します。逆に、ローカルストレージより指定したキーから値を読み込む処理にはgetItem(キー)メソッドを使用します。

キーについては、Vueインスタンスのデータオブジェクト内に追加してあげましょう。

また、JavaScriptのオブジェクトをJSON形式の文字列に変換する場合はJSON.stringify()メソッド、逆の場合はJSON.parse()メソッドを使用してあげると良いですね。

ウォッチャによる監視

では、どのタイミングでローカルストレージにデータを保存してあげればいいのでしょうか。

Vue.jsの場合、watchオプションの「ウォッチャ」機能を使用しましょう。 ウォッチャは特定のプロパティを監視し、データの変化に反応して処理を行います。

watch: {
  監視するプロパティ: function() {
    // 変化した時に行いたい処理      
  }
}

ネストした深い階層までデータを監視する場合は、deepオプションをtrueに設定します。

また、Vueインスタンス生成時にストレージに保存したデータを読み込む必要があるため、ライフサイクル関数(ライフサイクルフック)のメソッド(created())を使用しました。

ライフサイクル関数

Vueインスタンスの生成から破棄までのプロセスで自動的に呼びされる関数のことです。

created()の他にも、下記のメソッドが存在します。特定のタイミングに処理を実行したい場合はライフサイクル関数のメソッドを使用してあげると便利です。 ライフサイクル関数はmethodsの外に定義する点にだけ注意しましょう。

  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • beforeDestroy
  • destroyed

ChromeのDeveloperツールで「Application」を選択して確認すると・・・

f:id:b_leiu:20190825130950p:plain

ローカルストレージにtodosのデータが保存されていることが確認できますね。

最後に

以上で、Vue.jsの入門記事は終了です!

参考文献

いちばんやさしい Vue.js 入門教室

基礎から学ぶ Vue.js

Vue JS入門決定版!jQueryを使わないWeb開発 - 導入からアプリケーション開発まで体系的に動画で学ぶ