しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

knockout.js でカスタムバインディングを作成する

バインディングは text とか value みたいに data-bind 属性の内部で指定する奴です。knockout.js ではこのバインディングを自由に拡張できるようになっています。

バインディングは ko.bindingHandlers に内蔵のものもすべて含まれているので、ここに追加してあげればいいです。以下にテンプレを置いておきます。

ko.bindingHandlers.myBinding = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        // 初期化、イベントハンドラの登録など
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        // 値が変化した時に行う処理
    }
};

init は最初に一回だけ呼ばれるので、このタイミングでイベントハンドラの登録や初期値の設定を行っておきます。そして実際にバインディングしたプロパティの値が変化した時に update が呼ばれるので UI 要素への反映などを行います。

コールバックの引数は element に data-bind 属性を指定した DOM 要素、valueAccessor にバインディングされた値のアクセッサ、allBindingsAccessor に data-bind 属性に指定されたすべてのバインディング定義のアクセッサ、viewModel には指定したビューモデルが入ってます。

<span data-bind="myBinding: name"></span>

のように指定すると valueAccessor では name プロパティの値が取得できます。

アクセッサは関数なので呼び出すと実際の値が取れます。

// 値を取得
var value = valueAccessor();

// 全てのバインディング定義を取得
var allBindings = allBindingsAccessor();

valueAccessor で取れる値は大抵の場合は ko.observable なので、実際に値を取りたい場合には ko.utils.unwrapObservable を使えば楽です。

// 値を取得
var value = valueAccessor();

// observable から実際の値を取得
var valueUnwrapped = ko.utils.unwrapObservable(value);

後は何を実装するかなので、アイディアしだいですね。DOM 要素であればバインディング可能なので、audio/video 要素や canvas 要素向けのバインディングも作成することが出来るので、ある程度の処理をまとめたバインディングを作っておけば便利かもしれませんね。