0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-05-31

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

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

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

実際の開発環境は以下

  • jQuery1.xx
  • BootStrap 3.xx

HTML

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

<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(適当です。名前も適当)

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

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

Vue.use(VueLazyload, {
  preLoad: 1.3,
  error: 'dummy.png',
  loading: 'dummy.png',
  attempt: 1
});

当たり障りない感じに変えていますが、
実装の記述に近い形で書いています。もう少しスマートにできないものか、、、

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でも動きましたとさ。。。よかった。

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

おわり

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?