ちょっとした事情があって、Vue.jsを触ってみたので、感想とかはまった点とかを備忘録として残しておく。
ちょっとした事情
趣味と実益と暇つぶしを兼ねて、自宅のネットワークで運用しているWebシステムがある。
日記やら家計簿やら日々の案件管理やらをするのに使っていて、いわゆるLAMP(Linux, Apache, MySQL, PHP)で構築したもの。
インターネット上に公開しているわけではないのでセキュリティ面(XSS対策等)を考える必要もないし、別の誰かがメンテナンスするわけでもないのでコードの分かりやすさなんてのも不要。自分が構造を理解できていればいい。半分暇つぶしでやっているので、開発スピードを求めてもいない。
規模が極めて小さいということもあって、近頃の近代的なフレームワークなどは一切使用しておらず、バックエンドのPHPも、フロントエンドのHTMLもCSSもJavaScriptも、極めてプレーンな素の状態でコーディングしていた。
それがここにきてフレームワークを使ってみようと思ったきっかけは、こういう機能を作りたいと思ったから。
こんな表があったとして…
既存の表を元に別の表を動的に追加したり…
片方のデータを修正したらもう片方にも反映されるような動作をさせたい。
もちろん素のJavaScriptでElement.appendChildとかを駆使してゴリゴリ書いてもいいのだが、もっと楽に実現する方法はないかなぁと。
Vue.jsを選んだ理由
2020年現在のJavaScriptのフレームワークとしては、一般的に以下の3つが代表的なようだ。
- React
- Angular
- Vue.js
Angularは大規模開発向けで学習コストが高く、ReactやVue.jsは比較的小規模なところから始められる上に習得も容易という位置づけ。そのため、Angularは最初から候補から外れ、ReactとVue.jsのどっちを使うかということになる。
Vue.jsを選んだのは、公式の日本語ドキュメントが非常にわかりやすかったから。
このフレームワークを使うとどんなことが実現できるのかが、1ページにまとまっているのが素晴らしい。
また、素のJavaScriptで作られた既存のページにVue.jsのコードをちょっと追加するだけで使い始めることができ、利用のハードルが低いというのも魅力的だった。
実際に使ってみる
Vue.jsを既存のページに組み込むのは簡単で、<script>タグを一行追加するだけ。
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
ちなみに、これはCDN版の開発バージョン。jsファイル自体をダウンロードして、直接自分のサーバに置くこともできる。実際に運用を開始する際は、本番バージョンをダウンロードして使ったほうがいいと思う。
ドキュメントに記載されているように、以下のような構造のHTMLファイルを作れば、Vue.jsを動作させる準備は整う。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>...</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
</div>
<script>
// Vueインスタンス作成
var app = new Vue({
el: '#app',
data: {
},
methods: {
}
});
</script>
</body>
</html>
今回の私の用途では極めて小規模な使い方しかしないので、一つのHTMLファイルの中にすべてのコードを収めてしまった。
その場合、Vueインスタンスの作成部分は、対象のDOM要素よりも後に書く必要がある。そうしないと、Vueインスタンス生成時に以下のエラーが発生する。
[Vue warn]: Cannot find element: xxx
v-forディレクティブが使える要素について
ドキュメントを見ると、<li> や <div> に対しては、直接v-forを使ってループ処理ができると書かれている。では、例えば <table> を配列の要素の数だけループ処理して描画する場合はどうしたらよいのだろうか。
この場合、<template> に対してv-forを指定して、その中にループさせたい要素を入れていけばよいようだ。
<template v-for="item in items">
<table>
<tr>
<th>あいう</th>
<td><input type="date" v-model="item.x"></td>
</tr>
<tr>
<th>かきく</th>
<td><input type="text" v-model="item.y"/></td>
</tr>
</table>
</template>
v-modelとv-onの併用はNG?
ネット上には、v-modelとv-onを併用するのは良くない、という記事がいくつかみられるが、公式のドキュメント上にそのようなことが書かれている箇所は見つけられなかった。実際、併用しても普通に動いてしまったりする。
ただ、v-modelはあくまでもv-bindとv-onの糖衣構文なので、あえてv-onに書かなければいけない処理があるのなら、分けて書いた方が適切だろうとは思う。
<input v-model="searchText">
これは以下と同じことです:
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
変数の内容をサーバに送る方法の検討
プログラム上で変数をごにょごにょいじった後「さてサーバにPOSTするか」となったとき、はて、formに紐づけていない変数をどうやって送ればいいのか?となった。
よく使われるのは、Ajax(XHR)で非同期にサーバへデータを送るという方法らしいのだが、私は別に非同期通信をしたいわけではない。従来通り、formをsubmitする形でページを遷移できれば良い。
いろいろ考えた結果、適当なhiddenのform要素に、文字列化したJSONを突っ込んでsubmitするというやり方に落ち着いた。
こんなformとボタンを用意しておき、
<form id="send_form" method="post" action="hoge.php">
<input type="hidden" name="send_data" value="" />
</form>
<button v-on:click="submit_data">送信</button>
Vueインスタンスのメソッドに送信ボタン押下時の処理を書く。
var app = new Vue({
el: '#app',
data: {
hoge: "ああああ",
piyo: "いいいい"
},
methods: {
submit_data: function() {
// 送信するデータを単一のオブジェクトにまとめる
let send_data = {
hoge: this.hoge,
piyo: this.piyo
};
// 送信するデータをJSON文字列に変換
let send_data_j = JSON.stringify(send_data);
// formにJSON文字列をセットしてsubmit
document.forms.send_form.elements.send_data.value = send_data_j;
document.forms.send_form.submit();
}
}
});
受け取ったPHP側では、JSON文字列を$_POST変数から抜きだして、json_decodeで変数に展開すればよい。
<?php
$send_data_j = $_POST["send_data"];
$send_data = json_decode($send_data_j, true);
?>
コメント