Thymeleaf + jQuery + Vue.js  ここからはじめる（？）新しいフロント開発

# 0.はじめに（長い前置き）
Vue.jsの使い方そのものは公式ドキュメントが日本語で充実しているし、使い始めは公式のチュートリアルに沿っていけばいいので何書くかなーってことで
バックエンドを中心にやってきた人に向けて、SpringBootで作ったアプリにVueをちょこっと導入してみたらこんな感じ！というコードを書いてみました！

イマドキのフロント開発と行ったらNode入れてnpm入れてJavaScriptもES2015で書いてWebPackでコンパイルしてbabelでトランスパイルしてってちょっとまってまって無理無理無理！
てな感じで、まあ俺にはjQueryがお似合いさと世間の人が「jQueryはさすがにもう辛い」と言ってるのがピンとこないままjQueryを使い続けてた過去の自分に送るアドベント記事です。
（訳：異論は受け付けません）

## というわけで
**明らかにベストプラクティスではない**のですが、
こんなところからでも始められるよ、というのと、
ｊQueryで書いたときの違いがわかっていただけるのではないかなと思って書きました。

このコードのHTML、JavaScriptはコンパイルもトランスパイルもいらないです。
NodeもWebPackもBabelも使ってないです。（ついでにgulpも）。
怖くないですよ！


# 1. HTML（とpom.xml）

とりあえず先にHTMLを全文。解説は後でします。

```index:index.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はこんな感じ。

```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処理には敢えてｊQueryを使いました。
何もかもを新しくしなくても大丈夫だよ、ということで。


# 2. JavaScript

``` index.js
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側のソースはこんなんです。

```index
@GetMapping("")
public String index(Model model){	
	model.addAttribute("thymeleaf_value", "ValueFromJava!");
	return "index";
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113385/613db882-ea7b-6099-a6de-2820083d8851.png)

はい。表示されました。背景を白くすると画像の境目がわかりにくいですね。ごめんなさい（直さない）

## AddListをクリック
AddListをクリックしてみましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113385/917f61b1-80bf-87fe-c7d3-6929ff788745.png)

はい、1行増えました！

AddListのボタンに書いている`v-on:click="addList"`により、クリックイベントが発生するとVueで定義↓`addList`メソッドが実行されます。

```addList
addList:function(){
 this.datalist.push({id:this.datalist.length+1, color:'white'});
}
```

さて、ここでやっているのはdatalistに1要素追加しているだけです。
1行分のHTMLはいつ書かれたのでしょうか？

``` index.html(v-for)
<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`と入力してみましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113385/2449e036-e03d-f1d1-0b2d-b86c6a43cb30.png)

なんと背景が赤くなりましたね！
`<input type="text" v-model="d.color"/>`のv-modelの効果でテキストボックスの変更値が即座にcolorに反映されています。
そして`v-bind:style="{backgroundColor:d.color}`により`background-color`にテキストボックスで入力した値が設定されるわけですね。
ｊQueryで変更箇所の親要素を探してCSSを追加して・・・とかやらなくていいわけです。

細かいところでいうとテキストボックスやdivにidやnameを指定してないですけど問題なく動いてます。

# 4. Ajax処理

## GETして画面に反映
GET!ボタンを押してみましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113385/b8b003bb-e684-8c86-89b4-dffeb2606101.png)

明細が入れ替わりましたね。

`getlist`でajaxで取得してきたjsonのリストをそのまま`datalist`に代入しています。
datalistの変更に応じて画面がそのまま変わった、ということですね。

Java側のソースはこんな感じ。

```get
@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を書いていないので画面は何も変わりません。
サーバーサイドで受け取ったものをコンソールに出力しているだけです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/113385/4e6c2264-4953-edc1-27e1-68dd3365ab69.png)

うまく出力されましたね。
ここで言いたいのは、POSTするために画面の値をかき集めて変換して・・・ということをやらなくても`datalist`をそのまま投げるだけでOKということです！

ｊQueryでは画面には表示しないんだけどPOSTや判定に使う`<index type="hidden">`やらオレオレattributeを大量に使っていたんですが、Vueを使うようになってそれらがさっぱりなくなりました。
javaScriptの変数としてだけ持っていればよいのです。素晴らしいですね！

一応、Javaのソースも。

```post
@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を入れてデータストアにしてみたりとどんどん深みにはまってはいくのですが、やっていてとても楽しいです。

何よりサーバーサイドとクライアントサイドがスッパリわかれて非常にわかりやすくなりました。テストもやりやすいですよね。

来年はどんな年になるかな〜？


# 今回のソース

https://github.com/syukai/VuejsWithThymeleaf