4

シナリオ

RequireJS と KnockoutJS を使用してウィジェットを作成しています。ウィジェットはko.applyBindings(widgetViewModel, thisWidget)、インスタンス化されたときに呼び出します。ウィジェットは、サイトが Knockout 自体を使用しているかどうかに関係なく、サイトで使用できる必要があります。

問題

Knockout を使用するサイトにウィジェットをドロップすると、ウィジェットのko.applyBindings(siteViewModel)セットアップ後にサイトが呼び出されると、間違ったビュー モデルがウィジェットに適用されます。ウィジェットはsiteViewModel、目的の代わりに取得しますwidgetViewModel

これまでに試したこと

  1. ko.applyBindings(siteViewModel)ウィジェットのセットアップ前に発生するように呼び出しを並べ替えます。 これは機能しますが、ウィジェットの呼び出し方法に制限がかかるため、理想的ではありません。

  2. 正しいバインディング コンテキストを適用するウィジェットのカスタム バインディングを追加します (つまりwidgetViewModel、ウィジェットに返されます{controlsDescendantBindings: true}; 。残念ながら、サイトで使用される Knockout インスタンスは、ウィジェットで使用されるものと同じではありません (Require のため)。おそらくグローバル名前空間を調べて、サイトのインスタンスにアクセスします。

4

3 に答える 3

0

applicator メソッドをエクスポートするか、ViewModel プロパティとして含めることができる方法でウィジェットを作成することをお勧めします。

デモ

exports.widget = function(title){
    var self = this;

    self.title = ko.observable(title);

    self.apply = function(element){
        ko.applyBindings(self, element);
    };

    return self;
};

ウィジェットの HTML は次のようになります。

<h1 data-bind="text: title">Default</h1>

ここで、両方のユーザーに、ワークフローを妨げずに文書に含める方法を提供する必要があります。

非 KO ユーザーは、h1要素のコンテナーに単純にバインドできます (モジュールの名前が MyWidgets であるとしましょう)。

MyWidgets.widget("Not In KO").apply(document.getElementById('parentOfWidget'));

Knockout ユーザーは、それを ViewModel に含め、withバインディングを使用してコンテキストを与えることができます。

var ViewModel = function(){
    var self = this;
    self.widgetInstance = new MyWidgets.widget("In KO");
    self.thing = "Other Thing";
}

ko.applyBindings(new ViewModel);

HTML は次のようになります。

<div id="ko" data-bind="with: widgetInstance">
     <h1 data-bind="text: title">Default</h1>
</div>
<h2 data-bind="text: thing"></h2>

ウィジェットのどのプロパティとも競合しない他のプロパティを引き続き作成できることに注意してください。

(ps 誰か、より良い名前を考えて、apply私の投稿を編集してください)

于 2013-07-08T02:08:42.140 に答える
0

次のように、ウィジェットのカスタム バインディングを作成してみてはいかがでしょうか。

define(["knockout", "jquery"], function (ko, $) {
    var widgetViewModel = {
        title: "My Widget Titel"
    };
    var widgetWrapperHtml = "<div data-bind=\"mywidget: true\"></div>";
    var widgetHtml = $("<div data-bind=\"text: $data.title\"</div>");

    ko.virtualElements.allowedBindings.mywidget = true;
    ko.bindingHandlers.mywidget = {
        init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
            // Create the widget context:
            var widgetBindingContext = widgetViewModel;
            // Or uncomment this line to created a child context:
            // var widgetBindingContext = bindingContext.createChildContext(widgetBindingContext);

            ko.virtualElements.emptyNode(element);
            ko.virtualElements.prepend(element, widgetHtml[0]); 

            ko.applyBindingsToDescendants(innerContext, element);
        }
    };

    var applyWidgetToElement = function (element) {
        $(element).html(widgetWrapperHtml);
        ko.applyBindings({}, element);
    };

    return applyWidgetToElement;
})

次に、次のようにウィジェットを使用できます。

require(["mywidget", "jquery"], function (widget, $) {
    widget($('.widgetStyle')[0]);
});

しかし、これも好きです:

require(["mywidget", "jquery", "knockout"], function (widget, $, ko) {
    var viewModel = { title: "My App" };
    widget($('.widgetStyle')[0]);
    ko.applyBindings(viewModel);
});
于 2014-02-17T16:34:20.373 に答える