0.はじめに(長い前置き)
Vue.jsの使い方そのものは公式ドキュメントが日本語で充実しているし、使い始めは公式のチュートリアルに沿っていけばいいので何書くかなーってことで
バックエンドを中心にやってきた人に向けて、SpringBootで作ったアプリにVueをちょこっと導入してみたらこんな感じ!というコードを書いてみました!
イマドキのフロント開発と行ったらNode入れてnpm入れてJavaScriptもES2015で書いてWebPackでコンパイルしてbabelでトランスパイルしてってちょっとまってまって無理無理無理!
てな感じで、まあ俺にはjQueryがお似合いさと世間の人が「jQueryはさすがにもう辛い」と言ってるのがピンとこないままjQueryを使い続けてた過去の自分に送るアドベント記事です。
(訳:異論は受け付けません)
というわけで
明らかにベストプラクティスではないのですが、
こんなところからでも始められるよ、というのと、
jQueryで書いたときの違いがわかっていただけるのではないかなと思って書きました。
このコードのHTML、JavaScriptはコンパイルもトランスパイルもいらないです。
NodeもWebPackもBabelも使ってないです。(ついでにgulpも)。
怖くないですよ!
1. HTML(とpom.xml)
とりあえず先にHTMLを全文。解説は後でします。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script th:src="@{/webjars/vue/2.5.3-1/vue.js}"></script>
<script th:src="@{/webjars/jquery/1.11.1/jquery.min.js}"></script>
</head>
<body>
some contents<br />
<label th:text="${thymeleaf_value}"></label>
<div id="content">
<div v-for="d in datalist" v-bind:style="{backgroundColor:d.color}">
{{d.id}}
<input type="text" v-model="d.color"/>
</div>
<button v-on:click="addList">Add List</button><br />
<button v-on:click="postlist">POST!</button><br />
<button v-on:click="getlist">GET!</button>
</div>
<script th:src="@{/index.js}"></script>
</body>
</html>
v-for,v-on,v-model,v-bind
というのがVue.jsのキーワードです。
まあとりあえずおいときましょう。
Vue.js自体もJavaエンジニアにやさしくMavenリポジトリからWebJarで持ってきています。で<script src=....
でインポートです。普通ですね。
最後にindex.js
をインポートしています。処理の本体はこっちです。
あと、さりげなく<label th:text="....>
でThymeleafの構文を使ってJavaから値を持ってきました。合わせて動きますよ、ということで。
pom.xmlはこんな感じ。
<!-- https://mvnrepository.com/artifact/org.webjars/vue -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>vue</artifactId>
<version>2.5.3-1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/jquery -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>1.11.1</version>
</dependency>
今回はajax処理には敢えてjQueryを使いました。
何もかもを新しくしなくても大丈夫だよ、ということで。
2. JavaScript
var myVueapp = new Vue({
el:"#content"
,data:{
datalist:[{id:1, color:"white"}]
}
,methods:{
// 1行追加
addList:function(){
this.datalist.push({id:this.datalist.length+1, color:'white'});
}
// POST処理 datalistをそのまま投げる
,postlist:function(){
$.ajax({url:'/post'
,type:"post"
,data:JSON.stringify(this.datalist)
,contentType: 'application/json'});
}
// GET処理 受け取ったJSONをそのままdatalistに入れる
,getlist:function(){
var self=this;
$.get('/get'
,null
,function(data){self.datalist=data}
);
}
}
})
1行目、Vueのインスタンスを作っています。
で、その中でまずel。これはどのコンテンツをVueで扱うかの指定ですね。
ここでは#content
のDIV
を対象にしています。
次がdata
、これがVueで扱うデータ部。
methods
、これがVueのメソッドですね。
とりあえずこんなもんにしておきましょう。
3. 表示
さて、画面を表示してみましょう。
一応、Java側のソースはこんなんです。
@GetMapping("")
public String index(Model model){
model.addAttribute("thymeleaf_value", "ValueFromJava!");
return "index";
}
はい。表示されました。背景を白くすると画像の境目がわかりにくいですね。ごめんなさい(直さない)
AddListをクリック
AddListをクリックしてみましょう。
はい、1行増えました!
AddListのボタンに書いているv-on:click="addList"
により、クリックイベントが発生するとVueで定義↓addList
メソッドが実行されます。
addList:function(){
this.datalist.push({id:this.datalist.length+1, color:'white'});
}
さて、ここでやっているのはdatalistに1要素追加しているだけです。
1行分のHTMLはいつ書かれたのでしょうか?
<div v-for="d in datalist" v-bind:style="{backgroundColor:d.color}">
{d.id}}
<input type="text" v-model="d.color"/>
</div>
v-for="d in datalist"
によりdatalistの件数分これが繰り返されるようになっています。Thymeleafでいうところのth:each
ですね。
決定的な違いは、datalistの中身が変わったら即座に反映されるという点。
Vueではデータだけ変更すればHTMLは勝手に変わるんですね!
Vueでは、というかこれがイマドキのフロントエンドフレームワークの2-wayバインディングというやつですね。
テキストボックスへ入力
というわけで次はテキストボックスにred
と入力してみましょう。
なんと背景が赤くなりましたね!
<input type="text" v-model="d.color"/>
のv-modelの効果でテキストボックスの変更値が即座にcolorに反映されています。
そしてv-bind:style="{backgroundColor:d.color}
によりbackground-color
にテキストボックスで入力した値が設定されるわけですね。
jQueryで変更箇所の親要素を探してCSSを追加して・・・とかやらなくていいわけです。
細かいところでいうとテキストボックスやdivにidやnameを指定してないですけど問題なく動いてます。
4. Ajax処理
GETして画面に反映
GET!ボタンを押してみましょう。
明細が入れ替わりましたね。
getlist
でajaxで取得してきたjsonのリストをそのままdatalist
に代入しています。
datalistの変更に応じて画面がそのまま変わった、ということですね。
Java側のソースはこんな感じ。
@GetMapping("get")
public List<IdAndColor> get(){
List<IdAndColor> list = new ArrayList<IdAndColor>();
list.add(new IdAndColor(0,"blue"));
list.add(new IdAndColor(1,"navy"));
list.add(new IdAndColor(2,"yellow"));
return list;
}
POST
今度はPOSTしてみましょう。successfuncを書いていないので画面は何も変わりません。
サーバーサイドで受け取ったものをコンソールに出力しているだけです。
うまく出力されましたね。
ここで言いたいのは、POSTするために画面の値をかき集めて変換して・・・ということをやらなくてもdatalist
をそのまま投げるだけでOKということです!
jQueryでは画面には表示しないんだけどPOSTや判定に使う<index type="hidden">
やらオレオレattributeを大量に使っていたんですが、Vueを使うようになってそれらがさっぱりなくなりました。
javaScriptの変数としてだけ持っていればよいのです。素晴らしいですね!
一応、Javaのソースも。
@PostMapping("post")
public String post(@Valid @RequestBody List<IdAndColor> body
,BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "";
}
body.forEach(r->{System.out.println("id:"+r.id + ", color:"+r.color);});
return "";
}
5. あとがき
いかがでしたでしょうか。
なんとなく、「Vueできそう!」「いいなこれ!」と思っていただけたら嬉しいです。
次にコンポーネントを使うと画面の部品単位でHTML、Script、CSSをまとめて管理できるようになったり、こうするとnode,npm,webpackを入れてコンパイルしないといけなくなったり、それやりだすと親子関係のデータ管理が複雑になってくるのでVuexを入れてデータストアにしてみたりとどんどん深みにはまってはいくのですが、やっていてとても楽しいです。
何よりサーバーサイドとクライアントサイドがスッパリわかれて非常にわかりやすくなりました。テストもやりやすいですよね。
来年はどんな年になるかな〜?
今回のソース