Rのつく財団入り口

ITエンジニア界隈で本やイベント、技術系の話などを書いています。

【感想】『速習 Vue.js 3 速習シリーズ』:最速のVue3本&変更点所感

最速のVue.js 3 本!

 2020年9月19日にメジャーリリースされたフロントエンドJSフレームワーク、 Vue.js バージョン3.0を扱った最速の本。技術書では安心の山田祥寛さんの手軽に読める速習シリーズです。本エントリでは本の感想とv2→v3の主な変更点を書いていきます。

速習 Vue.js 3 速習シリーズ

速習 Vue.js 3 速習シリーズ

Part 1: イントロダクション

 JSの3大フレームワーク Angular/React/Vue.jsの立ち位置は変わらず、jQueryで管理するのが辛くなってくるレベルの複雑さでれば、もっとも手軽に導入できるのがVue.jsという紹介の仕方になっています。

英語のVue.js v3公式サイト。

v3.vuejs.org

日本語版はまだv2までとなっています。(本エントリ執筆時点)

jp.vuejs.org

Part 2: Vue.jsの基本

 現時点で英語版しかないVue.js3公式サイトでは、CDNからscriptタグで読み込んで開発する一番原始的なやり方は「プロトタイピングあるいは学習の目的」とし、Vue CLIを推奨しているとのこと。しかし本書では入門書の立場からCDN経由で使うやり方を基本として解説しています。ちょっとした組み込みならこちらも使うし、これで良いのではと思います。

一番の変更点はVueインスタンスの宣言の仕方。

Vue.createApp({
  data:function() {
    return {
      message: 'Vue.js 3。それは私です!';
    }
  }
}).mount('#vue-app-id-of-div-tag');

のように createApp関数とそれに繋がるmount関数で宣言。dataプロパティ部分はVueインスタンスでもVueコンポーネントと変わらず関数形式となりました。
{{}}のマスタッシュ構文、各種ディレクティブで v-text,v-html,v-bind,、算出プロパティのcomputedなどは変わらず。

f:id:iwasiman:20201009064432p:plain

Part 3: イベント処理

  • ボタン押下などのイベントは <button v-on:click="methodName()"></button>
  • メソッド側の引数に e(変数名はなんでも可) を取るとイベントが取れる。
  • <button v-on:click="methodName('やあ', $event)"></button>とすれば引数ありでもイベントが取れる。
  • イベントの伝播を阻止したるするイベント修飾子が .stop, .prevemnt, .capture,.self, .once, .passive など。複数設定可能。
  • キーボードからの入力を識別するキー修飾子。v-on:keyup.esc="methodName()" のように指定で各種。Alt+Enterなども取れる。
  • v-on:click.right="methodName()" のようにするとマウスのクリックイベントも取れる。

など。このへんはVue.js2とほぼ変わらずでした。

Part 4: フォーム開発

  • テキストボックスの内容の変更を双方向データバインディングでその場で表示したりできる v-model
  • ラジオボタンチェックボックス、セレクトボックスの指定例。
  • ファイル入力ボックスの例。これだけは特殊でJSから値を設定することはできず、バニラJSで普通にファイルアップロードする時と同じ。
  • v-model.number="propName"とすると、ふつうすべて文字列で扱われるところが最初から数値に。
  • v-model.trim="propName" で前後空白除去もできる。
  • v-model.lazy="propName" でイベント発生をキー入力でなくフォーカス移動のタイミングに遅らせることもできる。

など。v-modelの修飾子周りはけっこう忘れてました。単一チェックボックスの値はJS側では真偽値になりますが、これもtrue-valuefalse-valueという属性で変えられるというのも忘れていましたw
 とはいえこのへんもほぼVue.js 2 と変わっていません。大きく変わったのは、v-modelひとつの要素に複数適用可能になったこと。

Part 5: 条件分岐とループ

  • <div> タグなどに指定して表示非表示を切り替えられる v-if ディレクティブ。関連して v-elsev-else-if
  • 非表示にするのはスタイルに display:none が加わるだけなので描画コストが少ない v-show。通常こちらを優先して使う。
  • 繰り返しでよく使うv-forv-for="(value, key. i) in member" のようにするとインデックス番号も使える。
  • 繰り返しで何もしない要素は <template> を使う。
  • 既存の配列の中身を変更してもVue.js2では変更が検知できなかった。dataプロパティにsampleListという配列があったとして、
  Vue.set(this.sampleList, 1, "after value");

のように既定の静的メソッドを使うか、JS関数をVue.jsがラップしている splice/push/pop/shift/unshift/splice/sort/reverse を使う必要があった。
 Vue.js3ではここが改良。

this.samplelist[1] = "after value"; 

のように単純に中身を変えても変更が検知される。

Vue.js2の基本に入門していると「おおーこのデータバインディングすごい! これがVue.jsか...フロントエンドの時代なのか...」と震えながら読み進め、深く見ていってこの配列の中身の変更のところに来ると「なんだ万能じゃないのね」という、現実に戻るようなキモチになりがちでした。この配列やオブジェクトの中身の変更の検知の強化はありがたいところですね。

またtemplateタグの中身が単一タグでなくてもよくなったので

<template>
  <div>ロシアといえば</div>
  <div>スチェンカ!</div>
  <div>バーニャ!</div>
</template>

が可能になります。不要なdivタグネストが1つ減りますね。

Part 6: もっとデータバインディング

バインディングを深掘りする章。

  • v-bindによるVue側とHTML側のバーンディングは、JSオブジェクトを渡すと複数属性も可能。
  • v-bind:[dataPropName]= のように[]で囲って書くと、Vue側のdataプロパティのdataPropNameの値を動的に渡せる。(動的引数、Vue2.6から)
  • v-onceで一度だけバインド。
  • v-bind:stylev-bind:classCSSの装飾関係。
  • v-cloak をタグに設定しておくと、Vue側の描画が終わるまで display:none を適用して画面のちらつきを抑える事ができる。

動的引数の機能は知りませんでした。ここもVue3.0での変更はないですね。

Part 7: コンポーネント

お馴染みVueコンポーネントの章。

let vueInstance = Vue.createApp({ //各種オプション
});
vueInstance.component('hello-compo',{
  template: '<div>かすかすじゃなくて</div><div>かすみん</div>'
});
vueInstance.mount("#vue-app-id-of-div-tag");

のようにしてグローバルコンポーネントを作っていけます。Vue2は Vue.component({コンポーネントの指定}) のように静的メソッドでしたが、Vue3は明示的にインスタンスに紐づけるような形になりました。こちらの方が直感的なような気がします。

  • Vueインスタンス内の components: オプション内で指定するとローカル登録になり、そのVueインスタンスの中でしか使えない。このローカル登録の書式はVue2と同じ。
  • HTMLタグのコンポ―ネント指定時に、<hello-compo sample-prop="値を渡すよ"></hello-compo> のようにタグの独自属性で値を渡すと、コンポーネント側は対応する props プロパティで受け取れる。受け取るだけで変更不可。
  • この props は検証ルールも指定可能。
  • 子のコンポーネントのメソッド内で $this.$emit('parentInsMethodName', args); のようにすると親インスタンスのメソッドが呼べてイベントの伝達になる。
  • HTMLタグのコンポーネント指定時に、<hello-compo>すろっと</hello-compo> のように囲んで渡すと、このテキスト部分をコンポーネント側で内部のテンプレートに反映できるスロット機能。

グローバルコンポーネントの定義方法、ルート要素が不要になったのが大きな変更点です。

Part 8: もっとコンポーネント

Vue3の大きな3つの機能追加の章。

Composition API
  • 従来のVueインスタンス/コンポーネント内に data:, props:, computed:, methods:, のようにJSオブジェクトの キー: {値, 値, ...}形式でオプションを書いていたものは、Options API と改めて命名
  • 対になるのがComposition APIprops, template 以外は同じことを setup() メソッド内に書く。
let vueInstance = Vue.createApp({ //各種オプション
});
vueInstance.component('composition-api-sample',
{
  props: ['propName'],
  template: '<div>コンポジションAPI使おう {{msg.msg1}} {{msg2}}</div>',
  setup(props) {
    // データオブジェクトの定義:dataオプションに相当
    const msgObj = Vue.reactive({
      msg1: "メッセージ1だよ",
    });
    const msg2 = Vue.ref("メッセージ2だよ");
    
    // イベントハンドラーの定義:methodsオプションに相当
    const onClickEmptyBtn = function() {
      // ボタンないけどボタン押下時の処理
    };
    // 算出プロパティの定義:computedオプションに相当
    const allMessage = Vue.computed(function() {
      return msgObj.msg1 + msg2;
    });
    // 定義内容を全部、setupメソッドの戻り値でJSオブジェクト形式で返す
    return {msgObj, msg2, allMessage, onClickEmptyBtn};
  }
});
  • データの宣言は Vue,reactiveVue.ref と2通りある。
  • 何が嬉しいかというとデータオブジェクトもメソッドも算出プロパティも全部、標準的なJavaScript記法で一旦変数に書く。よって、生成部分をJSの純粋関数で分割したり、ふつうに外出しして複数コンポーネントで共通化したりできる。関数ベースなのでテスタブルにもしていける。

 ネットでも新機能の目玉として紹介されていたのがまずこちら。小さなコンポーネントだと従来のOptions API記法と特に変わらないのでメリットなし。大きなコンポーネントや大規模開発だと共通化で大きな力になるとのこと。
Vue2でもVueコンポーネントの共通部分を抜き出すmix-inという機能がありましたが、だいたい解説本の後ろの方に書いてある、けっこう付加的な高度な機能という印象でした。

 単純なJavaScriptの関数に切り出せるのだからこちらの方が直感的に理解しやすいし、工夫のし甲斐がありそうですね。サーバーサイドの言語でのなんとかFactoryクラス、GoFデザインパターンだとTemplate Methodパターンや Builder パターンのような、共通するdataやmethodsを作るような小さい関数をどんどん作ってプロジェクト全体で使い回すような工夫ができそうです。

 また全体的に関数ベース寄りになったことで、同じくJSフレームワークで今もっともシェアのあるReactになんか似てきたような? という感じも受けます。

テンプレート配下のコンテンツを別の場所に表示するTeleport
  template: '<div>魔法でテレポートしよう <teleport to="#msgArea">*いしのなかにいる*</teleport></div>'

のように指定すると、Vueインスタンスと配下のVueコンポーネントを囲う要素の外側、画面のHTML要素内のどこでもよい <div id="mesgArea"></div>表示内容をテレポートさせるという機能。
 今まではどうやってもVue.jsの支配下にあるルートのタグ(ふつうは<div>)の外側の世界には影響を及ぼせませんでした。(厳密にはdocument.getElementById(id)とかすれば取れますが。) Vue3からそれが可能になります。
業務システム的な画面だと、画面の一番上とか一番下にあるメッセージエリア的な場所に何か表示するとか、そういう用途かなと想像しました。

非同期処理の待ちメッセージを表示するSuspense

 HTMLのタグ記述部分に以下のように指定すると、ロードが完了するまで代わりのメッセージを出してくれるという機能。まだ実験的APIで将来仕様が変わることもあるそうです。

<div id="vueapp">
  <suspense>
    <template #default> <good-morning></good-morning> </template>
    <template #fallback> 魔王城で ( ˘ω˘)スヤァ </template>
  </suspence>
</div>

Part 9: ディレクティブ/プラグイン

Vue.directive('highlight', {
 // オプション
});
<div id="vueapp"><span v-highlight="xx">色が</span>変わるよ</div>

のようにv-*ディレクティブも自作できるという話。

またVueインスタンスに自作ディレクティブを追加するための標準的な仕組みがプラグイン

let samplePlugin = {
  install(app, options) {
    app.directive('highlight', {
    }),
  }
};

のように定義し、Vueインスタンスから使う側は

Vue.createApp({
  // オプション類
}).use(samplePlugin)
.mount("#vue-app-id-of-div-tag");

のように最後にuseメソッドで指定します。GitHubなどで公開されているVue.js専用のプラグインですね。

Part 10: コマンドラインツールVue CLI

本格開発ではよく使うことになるコマンドラインツール。npmからインストールする時の名前がvue-cliからvue/cliに変わっています。

> npm install @vue/cli
> vue create sample-app

のようにしてオプションを各種選んでいくとプロジェクトフォルダが自動生成されて各種設定ファイルも設定され、比較的簡単に内蔵Webサーバーで最初の画面も表示できるというもの。

 このオプションでTypeScriptも選べるようになっています。Vue2がReactと差を付けられていた理由の一つがこのTypeScript対応の遅れと言われています。Vue3でいよいよ正式対応を強化したとのことですが具合はどうでしょうか。各所のやってみた系のブログやQiitaやZenn記事などを見ていきたいところです。本書はすぐ読める入門書の位置付けなので、TypeScriptについての記述はありません。

 また単一ファイルコンポーネント(Single File Component: SFC)の定義方法も本書ではこの章で軽く記述されています。ここは特にVue3での変更はみられませんでした。

Part 11: ルーティング

SPA(Single Page Application)を実現する上で、リクエストURLを受けて表示内容を制御する仕組みとしてVue.jsが用意している標準的なルーターがVue Router。
Vue CLI必須ではありませんが本書ではVue CLIで作ったアプリケーション、.vueの単一ファイルコンポーネントで実装した場合を前提に解説しています。

  • Vue CLIでの新規プロジェクト生成時のオプションか、> vue add router で途中からインストール
  • /src/router/index.js ファイルに、JSのオブジェクト配列の形式でルーティング情報を定義。URLパラメーターの定義もここで。
  • 本体のVueインスタンス定義のmain.js内では、createApp(hogehoge) の後に .use(router) のようにして使うことを宣言
  • VueコンポーネントのHTML定義の中で、<router-link to="/hoge"></router-link> のようにリンク先を切り替えたり
  • Vueコンポーネント内のJS実装から遷移する場合は this.$router.push('/'); のように書く
  • URLのパラメーターはVueコンポーネント側ではpropsで受け取れる
  • 複数のビューを同時に配置したり、入れ子にするのも可能

Vueインスタンスの宣言方法がcreateApp()メソッドに変わるのに伴い、ルーターcreateRouter()メソッドを使うなど多少変更がありますが、ルーティングの根本的な所は特に変更なしかな?と読めます。

Part 12: Vuex

 1画面にコンポーネントが多数配置されるような複雑なアプリケーションで、データや状態を一か所で集中管理する仕組みとしてVue.jsが用意しているVuex(ビューエックスでなくてビューックス)の章。Vue2の本でもだいたい後の方に出てきました。
 本書では、全データの集中管理は必ずしも必須ではなく、必要十分ならコンポーネント内部で保持する形でも問題ないことを注釈しつつ、Vue CLIから作ったプロジェクトを例にとって説明しています。

 Vue CLIでの新規プロジェクト生成時にオプションを選ぶと、プロジェクトフォルダにmy-vuexフォルダが生成されて一式整備。こういう高度な仕組みは最初から組み込んでおいた方がよいのでしょうね。
 実際の例としては、フロントエンドのコード例の記事で必ずと言ってほど出てくる必殺の、ボタンを押すとカウンタの数字が上がっていくカウンタアップアプリ。ストアを定義し、ゲッター、ミューテーション、アクション...を実装していきます。
 createStore()など見慣れないメソッド名もありましたが、ここも原理的なところはVue3でも変更はないようです。

Appendix: Vue.js 3での変更点

変更点が最後にまとめられています。

  • Vueインスタンス生成は従来new演算子でやっていたが、Vue3ではcreateApp()メソッド。対応してVue RouterもcreateRouter()、VuexもcreateStore()が新設。
  • Vueインスタンスのdataオプションはオブジェクト形式、Vueコンポーネントのdataオプションはオブジェクトを返す関数と差あり。Vue3はすべてオブジェクトを返す関数に統一。
  • Vue.component()などstaticな関数はなくなり、すべてcreateApp()で作ったVueインスタンスのメソッドに統一。これで複数のVueインスタンスで違う設定も可能になる。
  • 特定のキー押下でメソッドを呼び出すv-onディレクティブで、キーコードは指定できなくなる。
  • {{式 | パイプ処理}} で指定していたフィルタオプションが完全廃止。

  • 目玉がComposition API

  • <teleport> でのコンテンツの任意位置表示。
  • <suspense> でのローディング表示。
  • template オプションで全体を囲う<div>タグ不要、複数のルート要素可能に。
  • 配列やオブジェクトの中身を更新した際のデータバインディング改善。

あとは本書には書いていないですが速度向上などなどでしょうか。

まとめ:Vue3の変更点が最速で概観できる本

 変化が速い技術領域で時折話題になるのが、商業本は出るまでに時間がかかるのでその間に次のバージョンが出てしまったりしてすぐ古くなるという話。フロントエンドのフレームワーク類がまさにそうなのですが、本書は電子版のみ、軽めの本という長所を生かした2020/10月時点で唯一最速のVue.js 3.0を扱った商業本です。
お値段も700円と手ごろですし、Vue.jsを触っている方は読んでおいて損はないと思います。

公式サイトにてサポートページもあります。

wings.msn.to

おまけ:Vue.js3の変更点諸々所感

★フィルタオプションは、UNIX/Linuxコマンドみたいで面白いなと思いつつも、自分も結局算出プロパティやメソッドを使うことが多かったです。やはり差別化がよくわからない機能はひっそりなくなったんだなあとおもいました。
 公式アナウンスではJS構文でない独自構文なので学習コストが増加する、構文解析が複雑になるのが理由と述べられていますね。

★やはり最大の目玉は各所のネット記事でも取り上げられていますが、Composition API。とはいえ単一のVueインスタンス/コンポーネント単位で比較すると従来のOptions APIと完全に等価なので、威力を発揮するのは大きいプロジェクトでいろいろ工夫を凝らして共通化したりしてからでしょう。
 既にフロントエンドの大規模開発を継続してやられている会社さんなんかは大抵Vue.js2に完全に適合して、ファイルは全部単一ファイルコンポ―ネント単位にして、ビルドやらなんやらも組み込んで...とやっているでしょうから、パッと一瞬でVue3に入れ替える訳にはいかず多少時間はかかるでしょうね。逆にこれから本格開発を始めるというプロジェクトはタイミング的に丁度良いでしょうね。
 Composition API周りをどう活用して共通化の工夫をしたか……なんて話はそのうちネットの各所に載りそうでもあるので、他力本願ですが楽しみにしたいと思います。

★配列やオブジェクトの中身を変更した際もバインディングが検知してくれるよう進化したのも嬉しいですね。多分最初からそうしてくれたほうが直感的だったと思います。僕もよく配列の中身を全部とっかえて明確に検知させたりしていたので、今後は少し楽になりそうです。

★単純なVueインスタンスであれば、createApp()経由にして、EL式の el: '#id-of-div-tag' のところをmount()メソッドにして、dataオプションの戻り値を関数に変えればそれで動くはずです。サンプル系をいろいろ試すのも面白いと思います。

★かくいう僕も1画面=1VueインスタンスCDN形式で直接読み込み、バンドルもなし、routerやVuexなど高度な仕組みは使わない...という縛りで作っている比較的小さなWebアプリケーションでVue3を試しにちょっと入れてみました。Options API形式はそのまま、宣言部分とdataの戻り値を変えていざ起動。
 するとcreatedになって、mountedになって... そこであえなくエラー。どうやらインスタンス内部でコンポーネントとして呼んでいたカレンダー類などのプラグインがまだVue3に対応していないのが原因のようでした。こういうケースはしばらくの間はありそうです。

★商業本がすぐ古くなるという話の解決策の一つが技術同人誌。技術書典のオンラインマーケットBOOTHで検索するとReactやVue.jsの本はけっこう見つかります。僕も過去幾つか拝見しましたし、Reactで名の知れた『りあクト!』シリーズあたりもそのうち読もうかなあなどと思っています。
最近の本というと技術書典8で『Vue 3 解体新書』、技術書典9の『改訂版 実践で学ぶ!Electron+Vue.jsでデスクトップアプリ開発あたりが明確にVue3を取り扱っています。

booth.pm booth.pm

2020年冬(公式Twitterによると11月とのこと)の技術書典10~では、Vue3を扱った本がもっと増えそうな感じもするので、そのへんも期待したいと思います。
 
 

iwasiman.hatenablog.com

iwasiman.hatenablog.com