実践knockout

61
実践 knockout @hakurai

Upload: kazuhiro-eguchi

Post on 26-Jun-2015

1.754 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: 実践Knockout

実践 knockout@hakurai

Page 2: 実践Knockout

自己紹介

•hakurai

•Backlog開発チーム@ヌーラボ

•関ジャバ

•hoge駆動

•奈良模型愛好会

Page 3: 実践Knockout

1/10 新機能リリース!

Page 4: 実践Knockout

knockoutをフル活用しました

Page 5: 実践Knockout

KNOCKOUTについて

•JavaScriptでMVVMを実現するフレームワーク

• jQueryには依存していない

•サポートブラウザ

• IE 6+, Firefox 2+, Chrome, Safari, others

Page 6: 実践Knockout

KNOCKOUTのコンセプト

•宣言型データバインディング

•UIの自動更新

•依存性追跡

•テンプレート

Page 7: 実践Knockout

宣言型データバインディング

•HTMLの要素とJavaScriptの値を結びつける

•data-bind属性を要素に追加するだけ

Page 8: 実践Knockout

data-bindの例

•div要素のテキストと vm.message の値をバインド

<div data-bind="text: message"></div>

vm = { message: ‘hello world!’};

ko.applyBindings(vm);

Page 9: 実践Knockout

<html xmlns="http://www.w3.org/1999/xhtml"><head> <script type="text/javascript" src="../lib/knockout-2.1.0.js"></script></head><body><div data-bind="text: message"></div><script type="text/javascript" src="script.js"></script></body></html>

(function(){ var vm = { message: 'hello world!' }; ko.applyBindings(vm);}());

hello world!を表示する例

Page 10: 実践Knockout

<html xmlns="http://www.w3.org/1999/xhtml"><head> <script type="text/javascript" src="../lib/knockout-2.1.0.js"></script></head><body><div data-bind="text: message"></div><script type="text/javascript" src="script.js"></script></body></html>

(function(){ var vm = { message: 'hello world!' }; ko.applyBindings(vm);}());

step1 data-bind属性を設定

Page 11: 実践Knockout

<html xmlns="http://www.w3.org/1999/xhtml"><head> <script type="text/javascript" src="../lib/knockout-2.1.0.js"></script></head><body><div data-bind="text: message"></div><script type="text/javascript" src="script.js"></script></body></html>

(function(){ var vm = { message: 'hello world!' }; ko.applyBindings(vm);}());

step2 ViewModelを定義

Page 12: 実践Knockout

<html xmlns="http://www.w3.org/1999/xhtml"><head> <script type="text/javascript" src="../lib/knockout-2.1.0.js"></script></head><body><div data-bind="text: message"></div><script type="text/javascript" src="script.js"></script></body></html>

(function(){ var vm = { message: 'hello world!' }; ko.applyBindings(vm);}());

step3 ViewとViewModelをバインド

Page 13: 実践Knockout

6種類+ のbinding

•visible binding

• text binding

•html binding

•css binding

•style binding

•attr binding

•custom binding

Page 14: 実践Knockout

visible binding

•要素の表示・非表示の切り替え

•いわゆるdisplay:noneのon/offの切り替え

•オブジェクトがtrueまたはnon-nullなら表示

• false, 0, null undefinedなら非表示

<div data-bind="visible: showMsg">hello world!</div>

Page 15: 実践Knockout

text binding

•オブジェクトをテキストとして要素に設定

<div data-bind="text: message"></div>

Page 16: 実践Knockout

html binding

•オブジェクトをinnerHTMLとして要素に設定

<div data-bind="html: message"></div>

vm = { message: ‘<strong>hello world!</strong>’};

Page 17: 実践Knockout

css binding

•要素のclassの追加・削除

•オブジェクトがtrueならclassを追加

• falseならclassを削除<div data-bind="css:{selected: status}"></div>

vm = { status: true};

Page 18: 実践Knockout

trueならclassを追加

<div data-bind="css:{selected: status}"></div>

vm = { status: true};

<div class=”selected”></div>

Page 19: 実践Knockout

falseならclassを削除

<div data-bind="css:{selected: status}"></div>

vm = { status: false};

<div></div>

Page 20: 実践Knockout

複数指定もできます<div data-bind="css:{selected: status, warn: over}"></div>

vm = { status: true, over: true};

<div class=”selected over”></div>

Page 21: 実践Knockout

style binding

•要素のstyleを設定

•css bindingがあるので余り使わないかも

<div data-bind="style:{color: bg}"></div>

vm = { bg: ‘red’};

Page 22: 実践Knockout

style bindingの注意点

•スタイル名に-(ハイフン)は使えない

•キャメルケースに書き換える

• font-weight → fontWeight

• text-decoration → textDecoration

Page 23: 実践Knockout

attr binding

•要素の属性を設定

•hrefとかsrcとか

<a data-bind="attr:{href: url}"></a>

vm = { url: ‘http://www.backlog.jp/’};

Page 24: 実践Knockout

custom binding

•好きな名前でbindingを自分で作れる

•これまで紹介したbindingも同じ仕組でできている

<div data-bind="hoge: message"></div>

ko.bindingHandlers.hoge = { init: function(){}, update: function(){}};

Page 25: 実践Knockout

UIの自動更新

•UIとオブジェクトの状態を同期する

•オブジェクトを同期するko.observable

•配列を同期するko.observableArray

Page 26: 実践Knockout

UIの自動更新

•ko.observableを使用していないプロパティは同期されない

vm = { name: ‘aoshima’, age: ko.observable(25)};

同期されない

同期される

Page 27: 実践Knockout

•ko.applyBindingsの呼び出し時の値でバインドされる

最初のバインド

vm = { name: ‘aoshima’, age: ko.observable(25)};

ko.applyBindings(vm);

name = ‘hasegawa’;age(26);

aoshima25

Page 28: 実践Knockout

•nameはko.observableでラップされていない

•値が変わっても更新されない

値の更新

vm = { name: ‘aoshima’, age: ko.observable(25)};

ko.applyBindings(vm);

name = ‘hasegawa’;age(26);

aoshima25

Page 29: 実践Knockout

•ageはko.observableでラップされている

•値が変わると自動的に更新される

値の更新

vm = { name: ‘hakurai’, age: ko.observable(25)};

ko.applyBindings(vm);

name = ‘hasegawa’;age(26);

aoshima26

Page 30: 実践Knockout

依存関係追跡

•オブジェクト同士に依存関係を持たせる

•ko.computed

•別のko.observableの値が変更されると更新される

Page 31: 実践Knockout

依存関係追跡

•ko.computedに渡した関数内のko.observableの値が更新されるとko.computedの値も更新される

function vm(){ this.firstName =ko.observable('Bob'); this.lastName =ko.observable('Smith'); this.fullName = ko.computed(function () { return this.firstName() + " " + this.lastName(); }, this); }

Page 32: 実践Knockout

テンプレート

•テンプレートを利用してオブジェクトを表示する

<div data-bind="template: { name: 'person-template', data: buyer }"></div> <div data-bind="template: { name: 'person-template', data: seller }"></div><script type="text/html" id="person-template"> <h3 data-bind="text: name"></h3> <p>Credits: <span data-bind="text: credits"></span></p></script>

vm = { buyer: { name: 'Franklin', credits: 250 }, seller: { name: 'Mario', credits: 5800 }}

Page 33: 実践Knockout

<div data-bind="template: { name: 'person-template', data: buyer }"> <h3 data-bind="text: name">Franklin</h3> <p>Credits: <span data-bind="text: credits">250</span></p></div> <div data-bind="template: { name: 'person-template', data: seller }"> <h3 data-bind="text: name">Mario</h3> <p>Credits: <span data-bind="text: credits">5800</span></p></div>

vm = { buyer: { name: 'Franklin', credits: 250 }, seller: { name: 'Mario', credits: 5800 }}

テンプレートが展開された

Page 34: 実践Knockout

Control flow

• foreach binding

• if binding

• ifnot binding

•with binding

Page 35: 実践Knockout

foreach binding

•配列分要素を繰り返し追加する

<ul data-bind=”foreach: users”> <li data-bind=”text: name”></li></ul>

vm = { users: [{name: ‘hoge’}, {name: ‘fuga’}]}

Page 36: 実践Knockout

foreach binding

•この例の場合 li 要素が2つ分表示される

<ul data-bind=”foreach: users”> <li data-bind=”text: name”>hoge</li> <li data-bind=”text: name”>fuga</li></ul>

vm = { users: [{name: ‘hoge’}, {name: ‘fuga’}]}

users配列分繰り返し

Page 37: 実践Knockout

foreach bindingと自動更新

•UIを自動更新する場合はko.observableArrayを使う

<ul data-bind=”foreach: users”> <li data-bind=”text: name”></li></ul>

vm = { users: ko.observableArray( [{name: ‘hoge’}, {name: ‘fuga’}] )};

Page 38: 実践Knockout

foreach bindingと自動更新

•pushで要素を追加すると li 要素も追加される

vm.users.push({name:‘piyo’});

<ul data-bind=”foreach: users”> <li data-bind=”text: name”>hoge</li> <li data-bind=”text: name”>fuga</li> <li data-bind=”text: name”>piyo</li></ul>

Page 39: 実践Knockout

if binding

•オブジェクトがtrueの場合に要素を追加する

<div data-bind=”if: show”> <span>hello world</span></ul>

vm = { show: ko.observable(false);}

Page 40: 実践Knockout

ifnot binding

•オブジェクトがtrueの場合に要素を追加しない

<div data-bind=”ifnot: notShow”> <span>hello world</span></ul>

vm = { notShow: ko.observable(false);}

Page 41: 実践Knockout

with binding

•バインディングコンテキストを変更する

<span data-bind=”text: title”></span><div data-bind=”with: data”> <ul data-bind=”foreach: users”> <li data-bind=”text: name”></li> </ul></div>

vm = { title: “hello” data: { users: [{name: ‘hoge’}, {name: ‘fuga’}] }}

Page 42: 実践Knockout

with binding

•vmオブジェクトのコンテキスト

<span data-bind=”text: title”></span><div data-bind=”with: data”> <ul data-bind=”foreach: users”> <li data-bind=”text: name”></li> </ul></div>

vm = { title: “hello” data: { users: [{name: ‘hoge’}, {name: ‘fuga’}] }}

Page 43: 実践Knockout

with binding

•vm.dataオブジェクトのコンテキスト

<span data-bind=”text: title”></span><div data-bind=”with: data”> <ul data-bind=”foreach: users”> <li data-bind=”text: name”></li> </ul></div>

vm = { title: “hello” data: { users: [{name: ‘hoge’}, {name: ‘fuga’}] }}

Page 44: 実践Knockout

with binding

•入れ子構造のオブジェクトにアクセスしやすくなる

•大きなViewModelを複数のオブジェクトに分割

<span data-bind=”text: title”></span><div> <ul data-bind=”foreach: data.users”> <li data-bind=”text: name”></li> </ul></div>

Page 45: 実践Knockout

コンテキスト変数

•$parent

•$parents

•$root

•$data

•$index

•$parentContext

•$context

•$element

Page 46: 実践Knockout

親のコンテキストにアクセス

•$parent

•$parents

•$root

•$data

•$index

•$parentContext

•$context

•$element

Page 47: 実践Knockout

foreach中のオブジェクト

•$parent

•$parents

•$root

•$data

•$index

•$parentContext

•$context

•$element

配列中のインデックス

Page 48: 実践Knockout

現在の要素

•$parent

•$parents

•$root

•$data

•$index

•$parentContext

•$context

•$element<div id=”item1” data-bind=”text: $element.id”></div>

item1

Page 49: 実践Knockout

working with form fields

•click binding

•event binding

•submit binding

•enable binding

•disable binding

•value binfing

•hasfocus

•checked binding

•options binding

•selectedOptions binding

•uniqueName binding

Page 50: 実践Knockout

click binding

•クリック人のイベントハンドラを設定する

<span data-bind=”text: message”></span><button data-bind=”click: onclick”>click me</button>

vm = { message: ko.observable(), onclick: function(data, event){ this.message(‘hello world!’); }}

Page 51: 実践Knockout

click binding

• foreach中の要素の場合引数に対応するオブジェクトが渡される

•基本的にevent.preventDefaultされる

•したくない場合は関数からtrueを返す

Page 52: 実践Knockout

イベントバブリング

•data-bind中で<イベント名>Bubbleを指定する

•クリックイベントのバブリングを止める場合

<button data-bind=”click: onclick, clickBubble: false”>click me</button>

Page 53: 実践Knockout

小ネタ

Page 54: 実践Knockout

仮想要素サポート

•コメントを使ってバインドを指定できる

•引数には更新後の値が渡される

<ul> <li>first</li> <!-- ko foreach: items --> <li data-bind=”text: $data”></li> <!-- /ko --></ul>

Page 55: 実践Knockout

ko.observable.subscribe

•ko.observableの値が変更された時に呼び出す関数を設定できる

•引数には更新後の値が渡される

this.count = ko.observable(1);this.count.subscribe(function(newValue){ alert(newValue);});

Page 56: 実践Knockout

スロットル拡張

•ko.observableの値が最後に変更されてから一定時間経った場合にUIを更新する

vm = { count: ko.observable(1).extend({ throttle: 5000})}ko.applyBindings(vm);

vm.count(2);

5 秒後に 2 に更新される

Page 57: 実践Knockout

• jQueryを使ったDOM操作を隠蔽したり

•使いこなすと結構便利

custom binding

ko.bindingHandlers.<バインド名> = { init: function(element,valueAccessor){ // applyBinding 時に一度だけ呼ばれる // 主に element に対してイベントハンドラを追加したりする }, update: function(element, valueAccessor){ // バインドしたko.observable()が変更されると呼ばれる // element を更新したりする }};

Page 58: 実践Knockout

ko.utils

•ko.utils.unwrapObservable

•ko.utils.arrayPushAll

•など

Page 59: 実践Knockout

•公式サイトのチュートリアル

•http://learn.knockoutjs.com/

•https://github.com/hakurai/knockout-sample

サンプルコード

Page 60: 実践Knockout

•http://hakurai.github.com/javap.js/web/

Page 61: 実践Knockout

•knockout便利!

まとめ