javascript - 自定义 knockout 绑定(bind)不起作用

标签 javascript mvvm knockout.js

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

当前事件与 viewModel 方法绑定(bind):

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

自定义绑定(bind)处理程序不起作用:

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

最佳答案

您的绑定(bind)正在尝试劫持默认“值”绑定(bind)的更新,从 knockout 源代码来看,该绑定(bind)似乎已被弃用。

'update': function() {}//保持与可能已包装值绑定(bind)的代码的向后兼容性

您必须更改绑定(bind),以便它改为使用 init。

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

编辑:

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

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的更新绑定(bind)告诉knockout在值更改时运行该代码。这在理论上听起来不错,但让我们来分解一下。

  1. 打开访问器并获取固定值。
  2. 创建一个返回格式化值的格式函数。
  3. 使用格式函数搭载值绑定(bind)。

因为这是一个更新绑定(bind),在步骤 1 中解包访问器会创建一个触发器,以便在访问器值发生更改时重新评估绑定(bind)。然后在第3步中,您告诉knockout重新执行value.update绑定(bind),该绑定(bind)当前只是一个空函数并且不执行任何操作。如果您将其更改为使用 value.init ,那么实际上可能会用于格式化输出,但您是在告诉 knockout 在每次值更改时重新初始化 init 绑定(bind)。

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

正在重新创建绑定(bind)并传递新的初始值。这也意味着它只是一种单向绑定(bind),因为对前端的更改无法返回到您的模型来更新支持的可观察值。

现在,如果您将自己的绑定(bind)更改为 init 绑定(bind),并从那里调用 value.init 绑定(bind),它只会初始化一次,但下一个问题是您绑定(bind)到的函数不是“不知道什么时候更新。

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 绑定(bind)计算的可观察值可确保对访问器可观察值的更新触发格式函数以从现有绑定(bind)内进行更新。

关于javascript - 自定义 knockout 绑定(bind)不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41901445/

相关文章:

java - 如何使用 MVVM 和 Retrofit 将存储库实现到我的项目中

c# - 如何在RDLC中格式化日期时间以本地日期时间格式显示?

android - 如何使用 DataBinding Framework MVVM 在 EditText 上设置错误

javascript - knockout 值在输入类型上绑定(bind)奇怪的行为

javascript - 使用 babel.js 而不是 browserify 编译成 bundle

javascript - 在 document.GetElementByID ('input' ).value = 'data[0]' 期间 DecodeForHTML,使用动态数组数据

javascript - 引号内的 If...Else 语句

javascript - 我可以在变量中捕获此文本吗?

当选择控件的源/选项更改时,JQuery 触发事件

javascript - 将函数链接到单击事件