こんにちはJJです。今回はVue.jsの機能の1つであるcomputedとmethodsの使い分けを意識して簡単な検索機能を題材として説明したいと思います。
Vue.jsとは
公式サイトでは、このように記述されております。
Vue (発音は / v j u ː / 、 view と同様)はユーザーインターフェイスを構築するためのプログレッシブフレームワークです。他の一枚板(モノリシック: monolithic)なフレームワークとは異なり、Vue は少しずつ適用していけるように設計されています。中核となるライブラリは view 層だけに焦点を当てています。そのため、使い始めるのも、他のライブラリや既存のプロジェクトに統合するのも、とても簡単です。また、モダンなツールやサポートライブラリと併用することで、洗練されたシングルページアプリケーションの開発も可能です。
Vue.jsはシングルページアプリケーション(SPA)をより効率的に開発するためのフレームワークです。簡潔に記述するための独自構文(ディレクティブ)が多く充実している点や、今回の記事では取り上げませんが、componentsによるカプセル化も大きな特徴であり、拡張性に富んだ面もあります。
実装例
早速、実装例を示したいと思います。前回の記事にて簡単な工作機械カタログを作成しましたが、今回は同様のものをVue.jsで実装してみました。これに加え、工作機械を検索する機能も追加しました。セレクトボックスから検索条件を選択し、テキストボックスに検索ワードを入力すると、それに対応する工作機械のみが表示されます。
https://s3-ap-northeast-1.amazonaws.com/machine-catalog/index_vue.html
サンプルコード
ソースコードはCSSを除き、HTML側にJavaScriptとJSONデータを記載しました。CSSはこちらのリンクを参照ください。
| 
					 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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96  | 
						<!DOCTYPE html> <html lang='ja'>     <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'>         <link href='./style.css' type='text/css' rel='stylesheet'>         <a href="https://unpkg.com/vue">https://unpkg.com/vue</a>         <title>Orizuru Machine Catalog</title>     </head>     <body>         <h1>Orizuru Machine Catalog</h1>  <div id="app"> <div>                     選択してください                     品番                     名称                     メーカー </div>             <table>                 <col width='5%' />                 <col width='45%' />                 <col width='25%' />                 <col width='25%' />                 <thead>                     <tr>                         <th>品番</th><th>画像</th><th>名称</th><th>メーカー</th>                     </tr>                 </thead>                 <tbody>                     <tr v-for='item in itemsFiltered'>                         <td>{{ item.itemID }}</td>                         <td>                             <img :src='item.image' /><br>                             <p>引用元:<a :href='item.url'>{{ item.url }}</a></p>                         </td>                         <td>{{ item.name }}</td>                         <td>{{ item.maker }}</td>                     </tr>                 </tbody>             </table>         </div>             var vue = new Vue ({                 el: '#app',                 data: {                     'selection': '',                     'keyword': '',                     'items' : [                         {                             'itemID': 1,                             'name': 'INTEGREX i-100',                             'maker': 'ヤマザキマザック',                             'image': './image/mazak.jpg',                             'url': 'https://www.mazak.jp/machines/integrex-i-100/'                         },                         {                             'itemID': 2,                             'name': 'ドライカットギヤシェーパSE25A',                             'maker': '三菱重工',                             'image': './image/mistubishi.jpg',                             'url': 'https://www.mhi-machinetool.com/products/detail/deburge_series.html'                         },                         {                             'itemID': 3,                             'name': '円筒素材を段付き加工 立形円筒研削盤 TAD',                             'maker': '牧野フライス精機',                             'image': './image/makino.jpg',                             'url': 'http://www.makinoseiki.co.jp/product/08_tad.html'                         }                     ]                 },                 computed: {                     itemsFiltered: function () {                         return this.findBy(this.items, this.keyword, this.selection)                     }                 },                 methods: {                     findBy: function (list, value, column) {                         return list.filter(function (item) {                             // 入力がない場合は全件表示                             return (item[column] == value || value === '')                         })                     }                 }             });     </body> </html></div>  | 
					
解説
一連のソースコードについて見ていきましょう。まずVueのフレームワークを有効にするべく、<head>にて下記のスクリプト文を入力します。下記のURLにアクセスすると分かると思いますが、Vueのソースコードがずらりと記述されており、これらをインポートすることによってVueのフレームワークを利用できます。
| 
					 1  | 
						<a href="https://unpkg.com/vue">https://unpkg.com/vue</a>  | 
					
次にスクリプト
| 
					 1  | 
						<div id="app">  | 
					
に関するVueインスタンスを生成します。
| 
					 1 2 3 4  | 
						var vue = new Vue ({ 	el: '#app', 	// 以下略 })  | 
					
これにより、その指定されたタグ内でVueの処理が適用されます。
一覧表示機能
続いて、工作機械の一覧表示機能について見ていきましょう。まずは簡単に全ての工作機械を表示する「全件表示」について考えてみましょう。実際のコードでは「itemsFiltered」とありますが、全件表示の場合は「items」に置き換えた状態で下記のコードによって実現できます。
| 
					 1 2 3 4 5 6 7  | 
						<tr v-for='item in itemsFiltered'>     <td>{{ item.itemID }}</td>     <td><img :src='item.image' /></td>     <td>{{ item.name }}</td>     <td>{{ item.maker }}</td>     <td><a :href='item.url'>{{ item.url }}</a></td> </tr>  | 
					
大まかな流れとしては下の図のようになります。ここでdataとはその名の通りデータオブジェクトの中の値を出し入れする入れ物であると解釈するとよろしいでしょう。
- 
① dataに保管されているJSONをHTMLタグのtrのv-for文によって工作機械の一覧としてテーブルにレンダリングされます。
 
ちなみに前回の記事ではjQueryによって全件表示を実現してます。こちらはコードの抜粋になります(ただしこちらでは「catalog_list.json」にデータを読み込んで処理してます)。
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  | 
						$(function(){                //HTMLを初期化     $("tbody").html("");     //HTMLを生成     $.getJSON("./catalog_list.json", function(data){         $(data.items).each(function(){             console.log('success to load')             $('<tr>'+                 '<td class="id">'+ this.itemID +'</td>'+                 '<td class="label"><img src = \"' +  this.image + '\" class=\"machine\"></td>' +                 '<td class="label">' + this.name  + '</td>' +                 '<td class="label">' + this.maker + '</td>' +                 '<td class="label"><a href = \"' + this.url + '\">' + this.url + '</a></td></tr>'              ).appendTo('table tbody');         })     })        });  | 
					
上記のjQueryのコードを下記の<tbody>にレンダリングしています。
| 
					 1 2 3 4 5 6 7 8  | 
						<table>     <thead>         <tr>             <th>品番</th><th>画像</th><th>名称</th><th>メーカー</th><th>引用元</th>         </tr>     </thead>     <tbody></tbody> </table>  | 
					
両者を見比べてみるとjQueryはJavaScript内でオブジェクトからDOMを生成しているのに対し、VueではHTML側に”{{ }}”で囲みその中にJavascriptとして直接オブジェクトを書き込むことで、すっきりしたコードを実現しています。
検索機能
次に検索機能について見ていきましょう。JSONデータの「itemID」とテキストボックスに入力したIDの両者が一致した工作機械のみを表示する機能をdataの他に算出プロパティ(computed)とメソッド(methods)を用いることで実現しています。computedとmethodsはどちらも最終的には同じ結果が得られるのですが、両者には大きな違いがあります。以下に両者の要点についてまとめます。
computed
- dataや他のcomputedの値が変化することで自動的に実行されるddd
 - 算出された値はキャッシュされ再利用される
 
methods
- 関数の置き場所として用いられる
 - 関数なので、呼べばそのまま実行される
 - 算出された値はキャッシュされない
 
さて、下の図を用いて具体的な処理について見ていきましょう。
- ① テキストボックスに入力することでディレクティブ「v-model」によってdataに「keyword」が保存されます。同様の原理によりセレクトボックスを選択した値も「selection」に保管されます。
 - ② 「keyword」と「selection」の値の変更によって「itemsFiltered」が自動的に実行され、「itemsFiltered」が「findBy」を実行します。
 - ③ 「itemsFiltered」が変化すると、自動的にHTMLにレンダリングされます。
 
おわりに
今回はVue.jsの中でもcomputedとmethodsによる簡単な検索機能について紹介しました。正直なところVue.jsフレームワーク独自の文法の理解に少々苦戦するかと思いますが、一度Vue.jsを習得するとその開発効率と融通性に惹かれるかと思います。また前回の記事ではjQueryによって実装しましたが、これに対し今回はVue.jsによって機能を実装しました。確かにjQuery等の他のフレームワークによる実装も十分可能ですが、ソースコードの可読性やメンテナンス性ではVueが優れている面があることをお分かりいただいたと思います。私自身も初心者なので、精進あるのみですね。以上です!!