こんにちは。新卒エンジニアの井餘田(いよた)です。
今回は、業務の中で触れた「Knockout.js」という JavaScript のフレームワークについて、簡単な例を挟みながらご紹介していきたいと思います!
はじめに
この記事では、ある程度の JavaScript についての知識は必要になってきますが、「Knockout.jsってなんなの?」とか「Knockout.jsっていうなんか便利なものがあるらしいけどよくわからん…」という方が「今日から使ってみたい!」と思うきっかけになればいいなと思っています。
ですので、ある程度 Knockout.js を知っている方には復習のつもりで見ていただけますと幸いです!
MVVMパターンとは
まずは Knockout.js を知る上で必須となる知識「MVVMパターン」について簡単におさらいしておきたいと思います。
MVVMパターンとは、簡単に言うとWebアプリケーション等の構造をModel(ビジネスロジック担当)、View(UI担当)、ViewModel(Viewの状態の保持担当)の3つに分けたパターンのことで、Model、View、ViewModelはそれぞれ下図のような関係になっています。
Model | 主にプログラマーが担当する範囲を指し、ビジネスロジック等の表示に関係ない裏のロジックを担当します。 |
View | 文字通り見た目(UI)を担当するもので、WebアプリケーションですとHTMLやCSSのことを指します。 |
ViewModel | 画面の表示全般に関わるロジックを持ち、View の状態やデータの保持を担当します。 |
こうして分けることのメリットとしては、プログラマーであればデータの取得や裏のロジックを担当し、デザイナーであれば UI などの見た目の部分を担当するといったように、開発者の役職によって担当箇所を分業できるという点です。
例えば、入力した ID によって登録したユーザーのデータを表示する Webアプリケーションを作った場合を考えてみましょう。
View にある入力フォームで ID を入力すると、ViewModel はその ID をもとにユーザーのデータを取得するように Model に依頼します。
Model は受け取ったIDをもとにデータベースからユーザーデータを取得し、その結果を ViewModel に返します。
ViewModel は受け取ったユーザーデータをViewに反映させることでユーザデータが画面に表示される、といった流れで「入力→表示」を制御しています。
それではMVVMパターンについて理解を深めたところで、今回の主題である「Knockout.js」について触れていきましょう!
Knockout.jsってなに?
Knockout.js とは、MVVM(Model-View-ViewModel) パターンをサポートするための JavaScript のフレームワークで、Knockout.js 自体が純粋な JavaScript で作成されている為、Webサイトや Webアプリケーション等に簡単に導入出来ます。
Knockout.jsは、View の内容と ViewModel の「状態保持オブジェクト」の紐づけをしてくれる役割を持ちます。
その為、ViewModel(状態保持オブジェクト)が持っているUIの状態の内容を監視し、このオブジェクトの内容をView側(HTML)に反映させたり、逆にView側の変化をオブジェクトに反映させることが出来ます。
さらに、一度紐づけが行われたら、以降は View/ViewModel のどちらか一方の状態が変化した場合も、リアルタイムでもう一方の状態も更新されるようになります。
このような構造は以下のようなメリットが生まれます。
- DOM(Document Object Model) 操作のための JavaScript コードがほとんど不要になる
- UI への入出力のために HTML 要素への id 設定が不要になる
Knockout.jsを
実際に書いてみよう
まずは、Knockout.js の導入方法です。
下記の1行で導入できるため、以下の CDN の方法がおすすめです。
<script type="text/javascript" src="knockout-3.0.0.js"></script>
それでは、Knockout.js の具体的な書き方について触れていきましょう!
ここでは、同じ内容のコードを JQuery で書いたパターンと Knockout.js で書いたパターンで比較していきます。
下記はどちらも「ボタンを押下するとリストの内容が追加される」といった内容になります。
JQuery
(HTML側)
<ul id="Items"></ul>
<button id="AddButton">要素を追加</button>
・・・
(JavaScript側)
<script type="text/javascript">
$('#AddButton').click(function () {
var $ul = $('#Items');
var $li = $('<li>hoge</li>');
$ul.append($li);
});
</script>
Knockout.js
(HTML側)
<ul data-bind="foreach: items">
<li data-bind="text: $data"></li>
</ul>
<button data-bind="click: addItem">要素を追加</button>
・・・
(JavaScript側)
<script type="text/javascript">
// 状態保持オブジェクト
var viewModel = {
// リストの中身に相当するデータ配列
items: ko.observableArray([]),
// HTML側から呼び出されるメソッド
addItem: function () {
this.items.push('hoge');
}
};
// 状態保持オブジェクトとHTMLテンプレートを紐づけする
ko.applyBindings(viewModel);
</script>
上記の例では、一見コード量が多くなっただけのように見えますが、注目してもらいたいのは Knockout.js を使ったコードでは一切 DOM の操作をしていないということです。
Knockout.js では、HTML側で「テンプレート」を定義し、「テンプレートの状態」は JavaScript 側に持たせる構造になっています。
「テンプレート」と「テンプレートの状態」は上記のデータバインドの仕組みによってお互いが紐づけられる為、テンプレートの状態(サンプルコードのitems
の値)を更新することによって「自動的」にHTML側のテンプレートに反映されます。
上記の Knockout.js のサンプルコードでは「foreach: irtems」や「items: ko.observableArray([])」等、見慣れないコードがあると思いますが、これは Knockout.js 固有のコードでデータバインドを行うための仕組みになります。
そこで、もう少し詳しく内容を知りたいという方の為に、Knockout.js の一部の機能を紹介したいと思います!
Knockout.jsの
様々なバインディング
Knockout.js ではデータバインドの仕組みを使って動的なデザインを作ることが出来ます。
今回はその中でも私が特に使っていたバインディングを紹介したいと思います!
visible
”visible” バインディングは下記の例のように要素の 表示・非表示 を切り替えるために使います。
<div data-bind="visible: isDisplayMessage">
メッセージ1
</div>
<div data-bind="visible: values().length > 0">
メッセージ2
</div>
・・・
<script type="text/javascript">
var viewModel = {
// "メッセージ1"表示
isDisplayMessage: ko.observable(true),
// "メッセージ2"非表示
values: ko.observableArray([])
};
// "メッセージ1"を非表示に
viewModel.isDisplayMessage(false);
// "メッセージ1"を表示
viewModel.isDisplayMessage(true);
// "メッセージ2"表示
viewModel.values.push("some value");
</script>
html
”html” バインディングは下記の例のように、対象となる要素の innerHTML に値を設定可能です。
<div data-bind="html: details"></div>
・・・
<script type="text/javascript">
var viewModel = {
// 最初は空
details: ko.observable()
};
viewModel.details("<em>詳細は <a href='report.html'>こちら</a> をご覧ください。</em>"); // HTML コンテンツが表示される
</script>
style
”style” バインディングは下記の例のように、要素に対してスタイルの追加・削除が可能です。
例えば、変数の値に対して「Aの時はスタイルを〇にする」「Bの時は△にする」といった動的なデザイン変更が可能になります。
<div data-bind="style: {
color: value() < 0 ? 'red' : 'black',
fontWeight: value() < 0 ? 'bold' : 'normal' }">
メッセージ1
</div>
・・・
<script type="text/javascript">
var viewModel = {
// "メッセージ1"は、黒で表示される
value: ko.observable(150000)
};
// "メッセージ1"は、赤の太字で表示される
viewModel.value(-50);
</script>
foreach
”foreach” バインディングは下記の例のように反復処理をさせたい配列などのまとまったデータを一括で表示可能です。
<table>
<thead>
<tr>
<th>First name</th>
<th>Last name</th>
</tr>
</thead>
<tbody data-bind="foreach: people">
<tr>
<td data-bind="text: firstName"></td>
<td data-bind="text: lastName"></td>
</tr>
</tbody>
</table>
・・・
<script type="text/javascript">
ko.applyBindings({
people: [
{ firstName: '山田', lastName: '太郎' },
{ firstName: '佐藤', lastName: '花子' },
{ firstName: '斉藤', lastName: '次郎' }
]
});
</script>
if
”if” バインディングは、前述の”visible”バインディングと同じような使い方になりますが、異なる点として要素に対してではなく下記のようにコメントで囲った箇所の表示・非表示に使うことが出来ます。
この逆として”ifnot”というバインディングも存在しますが、基本的にはelseとして使うことが多いようです。
<ul>
<li>このアイテムは常に表示させたい</li>
<!-- ko if: isDisplay-->
<li>アイテム1</li>
<!-- /ko -->
</ul>
・・・
<script type="text/javascript">
var viewModel = {
// "アイテム1"を非表示
isDisplay: ko.observable(false)
};
// "アイテム1"を表示
viewModel.value(true);
</script>
click
この “click” バインディングは下記の例のように、関連付けられた要素のクリック時に指定した JavaScript の関数を実行するイベントハンドラの追加が可能です。
<div>
<span data-bind="text: numberOfClicks"></span> 回クリックしました。
<button data-bind="click: incrementClickCounter">クリックして下さい</button>
</div>
・・・
<script type="text/javascript">
var viewModel = {
numberOfClicks : ko.observable(0),
incrementClickCounter : function() {
var previousCount = this.numberOfClicks();
this.numberOfClicks(previousCount + 1);
}
};
</script>
今回紹介したバインディングは一部ですが、もっと知りたいという方もいると思いますので、気になった方は以下のリンクを参照してみてください。
おわりに
いかがでしたでしょうか?
今回は Knockout.js について紹介させていただきましたしたが、今後は React.js や Vue.js などにも触れてみようと考えています。
最近は動的なデザインのサイトが多くみられるようになってきましたが、それを支える技術はまだまだ知らないことばかりだなと感じる今日この頃です。
ですので、実際にコードを書いてみてそれぞれの特性を知って使い分けていけるようにまずは気になった技術に触れてみるということをしていきたいと思います!
この記事が、見ている方の「気になる技術に触れてみる第一歩」のきっかけになれば幸いです。
それでは良いエンジニアライフを!
コメント