6

Knockout 拡張機能のknockout-secure-bindingを使用していますが、問題が発生しました。

特に、Object.definePropertyノックアウトes5 のように を使用する場合、 で変更イベントがトリガーされたときにバインディングの関数は呼び出されませvalueん。updateinput

私の単体テストはその特異性を示しています。これは機能します:

it("reads an input `value` binding", function () {
    var input = document.createElement("input"),
        evt = new CustomEvent("change"),
        context = { vobs: ko.observable() };
    input.setAttribute("data-sbind", "value: vobs")
    ko.applyBindings(context, input)
    input.value = '273-9164'
    input.dispatchEvent(evt)
    assert.equal(context.vobs(), '273-9164')
})

これ (knockout-es5 がプロパティを定義する方法) は機能しません。

it("reads an input `value` binding for a defineProperty", function () {
    // see https://github.com/brianmhunt/knockout-secure-binding/issues/23
    var input = document.createElement("input"),
        evt = new CustomEvent("change"),
        obs = ko.observable(),
        context = { };
    Object.defineProperty(context, 'pobs', {
        configurable: true,
        enumerable: true,
        get: obs,
        set: obs
    });
    input.setAttribute("data-sbind", "value: pobs")
    ko.applyBindings(context, input)
    input.value = '273-9164'
    input.dispatchEvent(evt)
    assert.equal(context.pobs, '273-9164')
})

後者の場合、前述のように、value.updateが呼び出されたときに呼び出されていませんinput.dispatchEvent

カスタムバインディングは独自の を返しているvalueAccessorため、問題はそれに関連していると思います。オブジェクトのプロパティでは機能するが、 では機能しないというのは特に奇妙に思えdefinePropertyます。

4

1 に答える 1

6

Knockout は、バインディングの式を処理する前に書き換えます。これは、「オブザーバブルでなくてもハンドラーが値を更新できるようにする書き込み関数を含む双方向バインディング」をサポートするためです。この部分は、Object.defineProperty定義されたプロパティをバインディングで機能させます。

これはko.expressionRewriting.preProcessBindingsメソッドに実装されています ( source )

このメソッドは、次のバインディング式を有効にします。

data-bind="value: pobs, checked: vobs"

以下に:

"'value':function(){return pobs },'checked':function(){return vobs },'_ko_property_writers':function(){return {'value':function(_z){pobs=_z},'checked':function(_z){vobs=_z}} }"

_ko_property_writers観察不可能なプロパティを設定するためのコードを含む、生成されたファイルに注意してください。

この魔法のプロパティに関するソースコードのコメントは次のとおりです。

// For those developers who rely on _ko_property_writers in their custom bindings, we expose _twoWayBindings as an
// undocumented feature that makes it relatively easy to upgrade to KO 3.0. However, this is still not an official
// public API, and we reserve the right to remove it at any time if we create a real public property writers API.

したがって、関数で同じロジックを再現する必要があるだけです。適切なライター関数を返すという名前のオブジェクトconvert_to_accessorsに新しいプロパティを作成する必要があります。result"_ko_property_writers"

Parser.prototype.convert_to_accessors = function (result) {
    var propertyWriters = {};
    ko.utils.objectForEach(result, function (name, value) {
      if (value instanceof Identifier || value instanceof Expression) {
        result[name] = function expidAccessor() {
          // expression or identifier accessir
          return value.get_value();
        };
        if (ko.expressionRewriting.twoWayBindings[name]) {
          var token = value.token;
          var context = value.parser.context.$data;
          propertyWriters[name] = function(_z) {
              context[token] = _z;
            };
        }
      } else if (typeof(value) != 'function') {
        result[name] = function constAccessor() {
          return value;
        };
      }
    });
    if (Object.keys(propertyWriters).length > 0)
        result["_ko_property_writers"] = function () {
           return propertyWriters;
        }
    return result;
};

免責事項: これは本番環境向けの実装ではありません! 何をする必要があるかを示しているだけです。両方のサンプル テストが作成されますが、プラグインの他の部分が壊れる可能性があります。value.parser.context.$dataまた、使用はちょっとハックなので、正しいコンテキスト処理にも細心の注意を払う必要があります。

于 2014-02-09T20:39:38.150 に答える