【Vue.js】配列の監視(Deep)がうまく動かないので小細工をしてみた
おはようございます。
ちょこちょこ Vue を触っていて
とても便利なのですが、配列の監視がちょっとかゆいところに手が届かない感じですね。
配列を監視する際に一番知りたいのは
- 何行目のどの項目が変更されたのか
- 変更前、変更後の値
なんじゃないかと思うのですが、単純にできません。
また、watch 関数の引数には oldValue, newValue が渡されてくるのですが、どちらも同じものになっています。(ばぐ?仕様?)
ということで、
ひとまず何行目が変更されたのか、チェックできるようにしてみました。
プログラムは前回のものを流用。
【Vue.js】テーブル内にドロップダウンリストを設置してみる
スポンサーリンク
プログラム
CSS
css/style.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @charset "UTF-8"; body { font-family:Helvetica,'Helvetica Neue','Mplus 1p','Hiragino Kaku Gothic Pro','ヒラギノ角ゴ Pro W3',Meiryo,メイリオ,Osaka,'MS PGothic'!important; font-size:12px; } h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6 { font-family:Helvetica,'Helvetica Neue','Mplus 1p','Hiragino Kaku Gothic Pro','ヒラギノ角ゴ Pro W3',Meiryo,メイリオ,Osaka,'MS PGothic'!important; } div#app .table-container{ height:250px; max-height:250px; overflow-y:auto; margin:10px0px; } |
CSSに変更ありませんが、一応。
html
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"xml:lang="ja"lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible"content="IE=edge"> <meta http-equiv="content-type"content="text/html; charset=UTF-8"> <title>Vue テーブルにドロップダウン</title> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"name="viewport"> <link rel="stylesheet"href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" /> <link rel="stylesheet"href="https://use.fontawesome.com/releases/v5.6.1/css/all.css"> <link rel="stylesheet"href="css/style.css"> </head> <body class="hold-transition fixed skin-blue-light sidebar-mini "> <div class="wrapper" > <div style="margin: 20px;"> <pre> Vue.js で テーブル内にリストボックスを設置するサンプル </pre> </div> <div class="container"> <div class="row"> <div class="col-xs-12"> <div id="app"> <div class="table-container"> <table class="table"> <thead> <tr> <th>No</th> <th>名前</th> <th>年齢</th> <th>性別</th> <th>種類</th> <th>好物</th> </tr> </thead> <tbody> <tr v-for="(item, index) in items"> <td><input type="text"v-model="item.no"></td> <td><input type="text"v-model="item.name"></td> <td><input type="text"v-model="item.age"></td> <td><input type="text"v-model="item.sex"></td> <td> <select v-model="item.selectedKind"v-on:change="selectChange" > <option v-for="option in item.kindList"v-bind:value="option.value"> {{ option.text }} </option> </select> </td> <td><input v-model="item.favorite"></td> </tr> </tbody> </table> </div> <div class="pull-right"> <button id="addButton"class="btn btn-success"v-on:click="add">追加</button> <button id="modButton"class="btn btn-primary"v-on:click="mod">更新</button> <button id="delButton"class="btn btn-danger" v-on:click="del">削除</button> </div> </div> </div> </div> </div> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="js/script.js"></script> </html> |
各項目も変更できるようにテキストボックスにしました。
javascript
js/script.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | var_kindList=[ {value:'01',text:'キジトラ'}, {value:'02',text:'長毛種'}, {value:'03',text:'ミケ'}, {value:'04',text:'サビ'}, ]; var_items=[ {no:'1',name:'そら',sex:'♂',age:'8',kind:'キジトラ',kindList:_kindList,selectedKind:"",favorite:'犬の人形'}, {no:'2',name:'りく',sex:'♂',age:'7',kind:'長毛種',kindList:_kindList,selectedKind:"",favorite:'人間'}, {no:'3',name:'うみ',sex:'♀',age:'6',kind:'ミケ',kindList:_kindList,selectedKind:"",favorite:'高級ウェットフード'}, {no:'4',name:'こうめ',sex:'♀',age:'4',kind:'サビ',kindList:_kindList,selectedKind:"",favorite:'横取りフード'}, ]; /** * Vueインスタンス生成 */ varapp=newVue({ el:'#app', data:{ 'items':_items, 'oldItems':[] }, watch:{ 'items':{ handler:function(newValue,oldValue){ oldValue=this.oldItems; this.oldItems=JSON.parse(JSON.stringify(newValue)); if(oldValue.length<newValue.length){ alert("行追加"); }elseif(oldValue.length>newValue.length){ alert("行削除"); }else{ for(leti=0;i<newValue.length;i++){ let oldJson=JSON.stringify(oldValue[i]); let newJson=JSON.stringify(newValue[i]); if(oldJson!=newJson){ alert((i+1)+"行目が変更されました"); } } } }, deep:true }, }, methods:{ add:function(event){ console.log("addButton click"); let no=this.items.length+1; this.items.push({no:no,name:'こなつ',sex:'♀',age:'8',kind:'キジトラ',kindList:_kindList,selectedKind:"",favorite:'布団'}); }, mod:function(event){ console.log("modButton click"); this.items.find((item)=>item.name==="こなつ").favorite="高いところ"; }, del:function(event){ console.log("dlelButton click"); this.items.splice(-1); }, selectChange:function(event){ console.log("Select Change"); }, }, created:function(){ console.log("created"); this.oldItems=JSON.parse(JSON.stringify(this.items)); } }) |
起動してみる
まとめ
変更前のデータを保持する変数を用意し、初期化時にデータをセットしてデータ変更時に更新していくという感じなのですが、
javascript は 単純に代入するだけだと、どちらの変数も同じものとして扱われるため、一度 Json(文字列)にパース、再度 Object にパースして代入してあげる必要があります。
(嚙み砕いてます)
そんでもって deep watch を定義して、新旧の比較を行えばどこが変更されたのかチェックができますね。
比較処理をもっと細かくすれば、どの項目が変更されたのかまでチェック可能です。
何かのお役に立てれば。
ではでは。
ディスカッション
コメント一覧
まだ、コメントがありません