レガシー環境でvue_v2.6 の仮想DOMで表を生成する

 # Vueでいい感じにしたいという動機

3年ほど前
とある業務の中で、JSON形式で取得したリストをjsでぶん回して表を生成することがありまして、
ただ、いい感じにソートとかできたら嬉しいという要望があり、
きっとこれはいちいち画面遷移するような挙動だと実現できない＆jQueryでDOMを書き換えするのも重くなりすぎる、、、

あ、そうだ仮想DOMってやつをやってみようと思って実装した備忘録です。
(実際に業務で使用したものを当たり障りない形に修正しています。)

### 実際の開発環境は以下
- jQuery1.xx
- BootStrap 3.xx

### HTML
　画面内ソートするためのinputタグなんかをベタで書いてます。これは参考用
table内のtbodyをv-forで回してリストを生成しています。（これは便利）

``` html
<div id="list" v-cloak>
	<div>
		<div>
			<div>
				<h4>人数（<span>{{sortedList.length}}</span>件）</h4>
			</div>
			<div>
				<div>
					<table class="table table-bordered">
						<tr>
							<th>管理番号</th>
							<td><input type="text" v-model="search01"></td>
							<td>
								<select v-model="sort01">
									<option value=""></option>
									<option value="asc">昇順</option>
									<option value="desc">降順</option>
								</select>
							</td>
							<th>氏名</th>
							<td><input type="text" v-model="search02"></td>
							<th>氏名カナ</th>
							<td><input type="text" v-model="search03"></td>
						</tr>
						<tr>
							<th>性別</th>
							<td>
								<select v-model="search04">
									<option value=""></option>
									<option value="男性">男性</option>
									<option value="女性">女性</option>
									<option value="その他">その他</option>
								</select>
							</td>
							<th>住所</th>
							<td><input type="text" v-model="search05"></td>
							<th>出身校</th>
							<td><input type="text" v-model="search06"></td>
						</tr>
						<tr>
							<th>趣味</th>
							<td><input type="text" v-model="search07"></td>
							<th>配偶者</th>
							<td><input type="text" v-model="search08"></td>
							<th>子供</th>
							<td><input type="text" v-model="search09"></td>
						</tr>
							<th>住まい</th>
							<td><input type="text" v-model="search10"></td>
							<td colspan="4"></td>
						</tr>
					</table>
				</div>
			</div>
		</div>
 </div>

<table class="table table-bordered">
	<thead>
		<tr>
			<th>写真</th>
			<th>管理番号<br/>フリガナ<br/>名前</th>
			<th>性別</th>
			<th>住所</th>
			<th>出身校</th>
			<th>趣味</th>
			<th>配偶者</th>
			<th>子供</th>
			<th>住まい</th>
		</tr>
	</thead>
	<tbody>
		<tr v-for="person in sortedList">
			<td><img v-lazy="person.photo" v-bind:alt="person.name" class="lazy" width="45" /></td>
			<td>{{person.id}}<br/>{{person.name_kana}}<br/>{{person.name}}</td>
			<td>{{person.gender}}</td>
			<td>{{person.address}}</td>
			<td>{{person.shcool}}</td>
			<td>{{person.hobby}}</td>
			<td>{{person.spouse}}</td>
			<td>{{person.child}}</td>
			<td>{{person.Housing}}</td>
		</tr>
	</tbody>
 </table>

・・・
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
```

### DATA
適当なJSON（適当です。名前も適当）
``` javascript
var membersList = [
{photo:"yamada.png",id:"0001",name:"山田太郎",name_kana:"ヤマダタロウ",gender:"男",address:"東京",shcool:"東京大学",hobby:"旅行",spouse:"いる",child:"なし",Housing:"賃貸マンション"},
{photo:"suzuki.png",id:"0002",name:"鈴木次郎",name_kana:"スズキジロウ",gender:"男",address:"神奈川",shcool:"横浜大学",hobby:"写真",spouse:"なし",child:"なし",Housing:"持ち家"},
{photo:"kobayashi.png",id:"0003",name:"小林花子",name_kana:"コバヤシハナコ",gender:"女",address:"京都",shcool:"立命館大学",hobby:"座禅",spouse:"いる",child:"いる",Housing:"持ち家"}
・・・];
```

### SCRIPT
　画面読み込み中に写真が読み込まれるのを待ってると、良さが損なわれる気がしたので、レイジーロード探して、実装しました。

``` javascript
Vue.use(VueLazyload, {
  preLoad: 1.3,
  error: 'dummy.png',
  loading: 'dummy.png',
  attempt: 1
});
```
当たり障りない感じに変えていますが、
実装の記述に近い形で書いています。もう少しスマートにできないものか、、、

``` javascript
var app1 = new Vue({
	 el:'#list'
	,data:{
		 search01:''
		,search02:''
		,search03:''
		,search04:''
		,search05:''
		,search06:''
		,search07:''
		,search08:''
		,search09:''
		,search10:''
		,sort01:''
		,members:membersList
	}
	,computed:{
		 filteredList01: function(){ //管理番号
			return this.members.filter(function(item){
				return item.id.indexOf(this.search01) > -1
			}, this)
		}
		,filteredList02: function(){ //氏名
			return this.filteredList01.filter(function(item){
				return item.name.indexOf(this.search02) > -1
			}, this)
		}
		,filteredList03: function(){ //氏名カナ
			return this.filteredList02.filter(function(item){
				return item.name_kana.indexOf(this.search03) > -1
			}, this)
		}
		,filteredList04: function(){  //性別
			return this.filteredList03.filter(function(item){
				return item.gender.indexOf(this.search04) > -1
			}, this)
		}
		,filteredList05: function(){ //住所
			return this.filteredList04.filter(function(item){
				return item.address.indexOf(this.search05) > -1
			}, this)
		}
		,filteredList06: function(){ //出身校
			return this.filteredList05.filter(function(item){
				return item.shcool.indexOf(this.search06) > -1
			}, this)
		}
		,filteredList07: function(){ //趣味
			return this.filteredList06.filter(function(item){
				return item.hobby.indexOf(this.search07) > -1
			}, this)
		}
		,filteredList08: function(){ //配偶者
			return this.filteredList07.filter(function(item){
				return item.spouse.indexOf(this.search08) > -1
			}, this)
		}
		,filteredList09: function(){ //子供
			return this.filteredList08.filter(function(item){
				return item.child.indexOf(this.search09) > -1
			}, this)
		}
		,filteredList10: function(){ //住まい
			return this.filteredList09.filter(function(item){
				return item.Housing.indexOf(this.search10) > -1
			}, this)
		}
		,sortedList: function(){ //ソート後のデータを返す算出プロパティ sortedList
			var copy = this.filteredList10.slice()
			if(this.sort01 === 'asc' ){
				//comparatorAsc01 メソッドをコールバックとして sort 関数に渡す
				return copy.sort(this.comparatorAsc01)
			}else if(this.sort01 === 'desc') {
				//降順に並べ替えるためのコールバック関数は comparatorDesc02
				return copy.sort(this.comparatorDesc02)
			}else{
				return copy
			}
		}
	}
	,methods:{
		comparatorAsc01: function(itemA, itemB){ //昇順
			if(itemA.id < itemB.id){
				return -1
			} else if(itemA > itemB.id){
				return 1
			} else{
				return 0
			}
		}
		,comparatorDesc02: function(itemA, itemB){ //降順
			if(itemA.id > itemB.id){
				return -1
			} else if(itemA < id){
				return 1
			} else{
				return 0
			}
		}
	}
});
```

## 結果

記述は改善の余地があると思いますが、
機能としては満足いただいていたかと思います。

本来、選んだあと画面が再リロードして検索結果が表示されることしかできなかったものが
選んだ瞬間に表が入れ替わる様は思わず「おお」となりました。
無事にIEでも動きましたとさ。。。よかった。

まだまだ世の中、レガシーな環境はあるということで、
少しずつ良くしていければいいなと思います。

おわり