自定义Knockout绑定无法正常工作

时间:2017-01-27 19:18:24

标签: javascript mvvm knockout.js

我目前正在使用事件绑定来格式化电话号码(转换为xxx-xxx-xxxx格式),我想创建一个可重复使用的自定义绑定,以便将来在我们的应用中使用。当前事件绑定工作正常,但我无法使自定义绑定正常工作。任何人都可以看看下面并告诉我我的问题吗?

使用viewModel方法绑定当前事件:

<input class="form-control" id="Phone"  type="text" 
       data-bind="event: {blur: formatPhone}, enable: isInputMode, value: Phone" />

self.Phone = ko.observable(model.MainPhone).extend({ maxLength: 20 });

self.formatMainPhone = function() {
        var tempString = self.Phone().replace(/\D+/g, "").replace(/^[01]/, "").replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3").substring(0, 12);
        self.Phone(tempString);
    }

不起作用的自定义绑定处理程序:

<input class="form-control max225" id="Phone" type="text" 
           data-bind="formatPhoneNumber: Phone, enable: isInputMode, value: Phone" />

self.Phone = ko.observable(model.MainPhone).extend({ maxLength: 20 });

ko.bindingHandlers.formatPhoneNumber = {
        update: function (element, valueAccessor) {            
            var phone = ko.utils.unwrapObservable(valueAccessor());
            var formatPhone = function () {
                return phone.replace(/\D+/g, "").replace(/^[01]/, "").replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3").substring(0, 11);
            }
            ko.bindingHandlers.value.update(element, formatPhone);
        }
    };

1 个答案:

答案 0 :(得分:0)

您的绑定试图劫持默认“值”绑定的更新,该绑定查看了淘汰源代码,似乎已被弃用。

'update': function() {} // Keep for backwards compatibility with code that may have wrapped value binding

您必须更改绑定,以便它使用init。

ko.bindingHandlers.value.init(element, formatPhone, allBindings);

编辑:

这可能更接近你想要的。而不是使用更新绑定,这将创建一个中间计算observable,然后使用value.init将文本框绑定到该。我们永远不需要更新绑定,因为计算将负责为您传播更改。

ko.bindingHandlers.formatPhoneNumber = {
    init: function (element, valueAccessor, allBindings) {            
      var source = valueAccessor();      
      var formatter = function(){
        return ko.computed({
          read: function(){ return source(); },
          write: function(newValue){
            source(newValue.replace(/\D+/g, "").replace(/^[01]/, "").replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3").substring(0, 12));
          }
        })
      };

      ko.bindingHandlers.value.init(element, formatter, allBindings);
    }
  };

编辑2 - 更多解释

使用formatPhoneNumber的更新绑定告诉knockout在值发生变化时运行该代码。这在理论上听起来不错,但让我们把它分解。

  1. 展开访问者并获得固定值。
  2. 创建一个返回格式化值的格式函数。
  3. 搭载使用格式函数的值绑定。
  4. 因为这是一个更新绑定,所以在步骤1中展开访问者会创建一个触发器,以便在访问者值发生更改时重新评估绑定。然后在第3步中,你告诉knockout重新执行value.update绑定,它当前只是一个空函数,什么都不做。如果你改变它来使用value.init而事实上可能实际上用于格式化输出,但是你告诉knockout每次值改变时重新初始化init绑定。

    update: function(element, valueAccessor, allBindings) {
        var phone = ko.utils.unwrapObservable(valueAccessor());
        var formatPhone = function() { return phone.replace(...)}
        ko.bindingHandlers.value.init(element, formatPhone, allBindings);
    }
    

    重新创建绑定并传递新的初始值。这也意味着它只是一个单向绑定,因为对前端的更改无法返回到模型以更新后备可观察对象。

    现在,如果您将自己的绑定更改为init绑定,并从那里调用value.init绑定,它只会被初始化一次,但下一个问题是您绑定的函数isn'我会知道何时更新。

    init: function(element, valueAccessor, allBindings) {
        var phone = ko.utils.unwrapObservable(valueAccessor());
        var formatPhone = function() { return phone.replace(...)}
        ko.bindingHandlers.value.init(element, formatPhone, allBindings);
    }
    

    由于它只是一个正常的js函数,它正在传递一个已经解开的平坦值,它总是会根据手机的原始值给出相同的结果。传递value.init绑定计算的observable,确保对accessor observable的更新触发format函数从现有绑定中更新。