【问题标题】:Knockout binding value.update not being called with custom binding and defineProperty没有使用自定义绑定和 defineProperty 调用敲除绑定 value.update
【发布时间】:2014-03-02 01:21:30
【问题描述】:

我有一个 Knockout 扩展,knockout-secure-binding,我们遇到了an issue

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

我的unit tests 说明了这一特殊性。这有效:

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')
})

这(作为淘汰赛-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

【问题讨论】:

    标签: knockout.js knockout-3.0 knockout-es5-plugin


    【解决方案1】:

    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,其中包含设置不可观察属性的代码。

    这里是关于这个神奇属性的source 代码注释:

    // 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 函数中重现相同的逻辑:您需要在名为 "_ko_property_writers"result 对象上创建一个新属性,该属性返回相应的编写器函数:

    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 有点 hacky。

    【讨论】:

    • 太棒了。 Very helpful。干杯。
    • 值得注意的是,Knockout 只暴露了_twoWayBindings(即不暴露twoWayBindings)。见KSB/issues#29。干杯。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多