Vue.jsを使う場合と使わない場合をコードとして見比べる。
前回(3回目)の投稿から2か月も経過してしまったモミジの「スキル、なんだっけ?」の管理人ことかまぼこです。
私生活のことはさておき、前回はモミキん作成を効率的に進めることができたフレームワークVue.jsが従来のjavascriptやjQueryとどう異なるか、をアバウトに説明しました。
前回の話の中で、古いjavascriptでは見た目を制御するコードを多数書く必要があり、Vueではそこから脱却できたといいましたので、今日はモミキんの検索IF部分の核部分をサンプルに具体例を示してみようかと思います。
<!-- 見た目部分のコード --> <div id="app"> <div v-for="(selected, index) in selects"> <span @click="Delete(index)">[-]</span> <select v-model="selected.Effect"> <option v-for="option in Effects" v-bind:value="option.value"> {{ option.text }} </option> </select> </div> <span> <input @click="Add" type="button" value="条件追加"/> </span> </div> <!-- 制御関係のコード --> <script> const app = new Vue({ el: '#app', data: { selects:[{}], // 検索条件の効果詳細情報を持つ連想配列の配列 Effects:[ // 人様用の効果名称とDBに登録してある効果名称の変換用テーブル {text:"未選択", value:null}, {text:"変換", value:"変換"}, // ...省略 ], }, methods: { Delete(index) { // 検索条件からindex番目の要素を取り除く this.selects.splice(index, 1); // Vueに配列内の変更を通知するためにこの記法 }, Add () { // 検索条件を新たに追加する this.selects.push({}); }, } }; </script>
上記のコードは、検索項目を足したり減らしたりするための実際のコードです。 記憶が確かなら、IF部分の出だしはこんなところから始まったはずです。(git管理し始めたのだいぶ後なので詳細なログがない!!)
<div v-for="(selected, index) in selects" >
一番に感動したのはこの部分です。 v-forという属性に xxx in yyyという値を入れることで、Vueのdata要素で定義したyyyという配列の中身をxxxとして展開してくれます。カッコ書きで(selected, index)と書くことで何番目の要素であるかもindexに覚えててくれます。
これで、app.data.selectsにデータを足したり(Add関数)削除する(Delete関数)だけで、検索項目を増減させられます。
次のコードで、selectes配列内の各連想配列にデータをセットする方法ですが、これは以下のようなコードで実装されています。
<select v-model="selected.Effect"> <option v-for="option in Effects" v-bind:value="option.value"> {{ option.text }} </option> </select>
v-model="selected.Effect"と言うのが、select要素のvalueとselected.Effectに紐づけてくれます。 select要素内のoptionリストの生成は先ほどと同様v-forに配列を渡すことでできます。
Vueを使って最も感動をしたのは、v-forやv-bindみたいにHTMLからJavascript内の変数を呼び出したり紐づけたりできることです。 昔のjavascriptやjQueryでこれはできませんでした。
もし、最初のコードを古い書き方をすると(あくまでイメージですが)下記のようになると思います。
<div> <div id="検索条件"> <!-- N個目の検索条件の詳細を記述するためのHTMLをここに書けない --> <!-- 今、検索条件がいくつあるのかを知っているのはjavascriptだけであり、HTMLはjavascriptが持つ変数を関知しないから --> </div> <span> <input click="Add" type="button" value="条件追加"/> </span> </div> <script> // わずかでも簡略化するため(うろ覚えな)jQuery(的)な書き方で let selects = []; // 検索条件の効果詳細情報を持つ連想配列の配列 let Effects:[ {}, {} ]; // 人様用の効果名称とDBに登録してある効果名称の変換用テーブル const form = $("#検索条件"); fuction WriteSelects() { let div = $("<div>"); for (let i = 0; i < selects.length; i++) { let selected = $("<div>"); selected.append($("<input>", { click:"Delete(" + i + ")", text:"[-]" } )); const list = EffectSelectList(i); // listの初期選択値をselects[i].Effectとなるようにする処理をここに書く selected.append(list); div.append(selected); } form.html(div.html()); } function Add() { selects.push({}); WriteSelects(); } function Delete(index) { selects.splice(index, 1); WriteSelects(); } function EffecSelectList(index) { const id = "Effect" + index; const change= "ChangeEffect(" + index + ")"; let options = $("<select>", {change:change, id: id}); // 選択要素が変わったときにJavascriptに通知するように変更時呼び出される関数を(この要素だと特定できる引数と合わせて)定義する for (let i = 0; i < Effects.length; i++) { options.append($("<option>", {value:Effects[i].value, text:Effects[i].text})); } } function ChangeEffect (index) { selects[index].Effect = $("#Effect" + index).value; } </script>
ざっくりVue.jsではJS部分が20~25行程度、古い書き方では(関数を一部省略してなお)35~40行程度となりました。 古い書き方の一番面倒なところは、WriteSelectsとEffecSelectListのようにHTMLを記述するJavascriptがあるところです。さらにこの構造を複雑にする要因に、JavascriptでHTMLを書き、そのHTMLからJavascriptを呼び出すための属性を付与していることも挙げられます。
古いJavascriptとVue.jsのコードを比べると、共通のロジックはAdd()とDelete()と配列宣言部だけであることと、Vue.jsではVue関連の宣言を除くと共通部しかないことがわかります。
一方、Vue.js側のHTML部分は15行程度、古いJavascriptでは7行程度とHTMLは古い書き方の方が一見短くシンプルに見えます。 しかし前回の記事でも説明したように古い書き方ではJavascript内にHTMLを記述するコードが多くなり、今回で言えばそれは(35 - 20 = )15行程度あることが分かります。
コードの総量的な意味でもVue.jsに軍配が上がりますがそれ以上に、見た目的な話をJavascript内に持ち込まざるを得ない古い書き方ではHTMLを見てもどんなサイトなのか想像することができません。
仮想DOMも考えると描画速度のメリットもVue.jsにはあるような気はしますが、直接比較したことないのでそんな気がするよ程度で。
最後に、Vue.jsの良い点を再三になる部分もありますがまとめますと、
- Javascript内にHTMLを書かなくて済む
- 上記のおかげで、Javascriptを呼ぶHTMLをJavascriptで書く、ということがなくなる
- 見た目の記述はすべてHTMLやCSS、利用データ部分はdata部、ロジック部はmethodos、computed部に切り分けられる
- 複雑な構造になるほど記述量が古い書き方より少なく済む
- 描画速度が多分速い
なんてことが言えるかなと思います。 こんな良いところ(悪いところでも)があるよ! という話があればぜひ教えてください。
ではでは~。