Knockout绑定value.update没有使用自定义绑定和defineProperty调用

Bri*_*unt 6 knockout.js knockout-es5-plugin knockout-3.0

我有一个Knockout扩展,knockout-secure-binding,我们遇到了一个问题.

特别是在使用时Object.defineProperty,如knockout-es5所做的那样,当在一个触发更改事件时,不会调用value绑定的update函数input.

我的单元测试说明了它的特殊性.这有效:

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')
})
Run Code Online (Sandbox Code Playgroud)

这(敲除-s5定义属性的方式)不起作用:

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')
})
Run Code Online (Sandbox Code Playgroud)

在后一种情况下,如上所述,value.update在调用时不会被input.dispatchEvent调用.

自定义绑定返回自己的valueAccessor,所以我希望问题与此相关.它只是让我觉得特别奇怪,它可以使用对象属性,但不是defineProperty.

nem*_*esv 6

Knockout在处理它们之前会重写绑定事务,以便支持"双向绑定以包含允许处理程序更新值的写入函数,即使它不是可观察的值".此部分使Object.defineProperty定义的属性在绑定中起作用.

这是在ko.expressionRewriting.preProcessBindings方法()中实现的

此方法将转换以下绑定表达式:

data-bind="value: pobs, checked: vobs"
Run Code Online (Sandbox Code Playgroud)

以下内容:

"'value':function(){return pobs },'checked':function(){return vobs },'_ko_property_writers':function(){return {'value':function(_z){pobs=_z},'checked':function(_z){vobs=_z}} }"
Run Code Online (Sandbox Code Playgroud)

请注意生成的_ko_property_writers内容包含用于设置不可观察的proeprties的代码.

以下是有关此魔术属性的代码注释:

// 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.
Run Code Online (Sandbox Code Playgroud)

因此,您只需要在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;
};
Run Code Online (Sandbox Code Playgroud)

免责声明:这不是一个生产就绪的实施!它只是展示了需要做什么的想法.虽然它会进行两个示例测试,但它可能会破坏插件的其他部分.您还应该特别注意正确的上下文处理,因为使用value.parser.context.$data有点hacky.

  • 真棒.[非常有帮助](https://github.com/brianmhunt/knockout-secure-binding/commit/6263979f9dc111ad847d8f2b83bcfa6fa6f2453f).干杯. (2认同)