【问题标题】:Knockout Extension Issue - Better Solution?淘汰赛扩展问题 - 更好的解决方案?
【发布时间】:2015-05-27 15:35:10
【问题描述】:

我是淘汰赛新手,仍在学习如何最好地使用它。我在一个应用程序中有一些输入字段,它们与一堆实时更新的计算相关联。他们自己的领域很好,一切都很好......

除了,我需要在用户输入时格式化输入,仅用于显示(原始数据必须保留用于计算,但 3 应显示为 3% 或在另一个字段中 3000000 应显示为 3,000,000 等) .我有这个有点工作,但我认为我的解决方案存在一个重大缺陷,因为结果始终存在错误,并且有可能完全破坏输入字段。

因此,一个输入字段的示例,它与另一个字段相关联以始终等于 100%:

<input id='sm' data-bind='textInput: s_smixe' readonly='true'>

绑定到:

self.s_smixebase = ko.observable(30);
self.s_smixe = ko.pureComputed({
    read: function(){
        return this.s_smixebase();
    },
    write: function(value){
        if (parseFloat(value)<100) {
            var otherValue = 100 - parseFloat(value);
            this.s_smixebase(value);
            this.s_rmixebase(otherValue);
        } else {
            value = 100;
            this.s_smixebase(value);
            this.s_rmixebase(0);
        }
    },
    owner: this
}).extend({percent:{}});
self.s_smixeraw = self.s_smixe.raw;

然后扩展:

ko.extenders.percent = function(target) {
    var raw = ko.observable();
    var result = ko.computed({
        read: function() {
            var value = target();
            if (value.toString().indexOf('%')===-1){
                raw(parseFloat(value));
                value = value + '%';
                return value;
            } else {
                value = value.replace('%','');
                raw(parseFloat(value));
                value = value + '%';
                return value;
            }       
        },
        write: target
    }).extend({notify:'always'});
    result.raw = raw;
    return result;    
};

所以,这里发生的情况是,用户输入的第一个字符格式正确,用户输入的第二个字符消失,第三个加入第一个字符并正确格式化。如果字段是计算的或常规的 observable,也会发生同样的情况,并且计算的代码在没有应用扩展的情况下工作正常。因此,要输入 77%,您必须输入 7 - X - 7(其中 X 可以是任何值,因为它会在某个地方丢失到进程中)。

还应该注意的是,我在这个应用程序中使用了一个虚拟 javascript 数字键盘,所以我通过 javascript 添加值(虽然这并没有影响任何其他功能,所以我不确定为什么会在这里) .

任何人都可以就我做错了什么提供建议吗?我错过了什么导致输入如此错误?我真的决定不放弃这种实时输入格式的概念,因为它可以使演示更清晰,但如果必须,我只会在模糊上进行格式设置。

提前感谢您的任何建议。

【问题讨论】:

  • 我做了一个simple fiddle with your code... 它似乎运行正常,虽然我没有做虚拟键盘的事情。所以除非我歪曲了你想要做的事情,在那个小提琴中,看起来问题可能出在键盘上?
  • @Retsam 也差不多,只是这个app里的输入域也是显示域(所以s_smixebase是不显示的,s_smixe是绑定到活动输入域的),所以我在做在字段中输入时将此格式设置为输入。但是知道它是孤立地工作是非常有帮助的!感谢那!我会到处玩,看看是不是键盘问题。
  • 这不应该在扩展器中完成,它应该是一个绑定处理程序。当您想要扩展可观察对象的能力时,应该使用扩展器。当您想要更改与它们交互的方式时,应该使用绑定处理程序。
  • @JeffMercado 啊哈!好的。那么关于那个的问题。由于我需要 textInput 的功能(即时更新等),我该如何最好地增强它/什么是最佳实践?
  • 您想要做的与此问题中讨论的非常相似:stackoverflow.com/questions/30406535/… 请注意,当您重新格式化您正在输入的内容时,光标位置可能会出现困难。

标签: javascript knockout.js knockout-extensions


【解决方案1】:

因为当格式化功能替换您键入的内容时,正确定位光标很棘手,所以我建议您使用具有两种模式的字段:一种是您正在输入的地方,另一种是您正在输入的地方它显示格式化的值。哪个显示取决于光标焦点。

<div data-bind="with:pctInput">
<label>Value</label>
<input class="activeInput" data-bind='textInput: base, event:{blur:toggle}, visible:editing, hasFocus:editing' />
<input data-bind='textInput: formatted, event:{focus:toggle}, visible:!editing()' readonly='true' />
</div>

这里有一个工作示例: http://jsfiddle.net/q473mu4w/1/

【讨论】:

    【解决方案2】:

    因此,对于以后遇到此问题的任何人,我最终使用了 @RoyJ 解决方案的修改版本,该解决方案来自最初的 cmets 中提到的线程。如果我要在更大的项目中使用它,我确实需要想出一种方法来实现这种规模,但这对于少量输入的东西来说已经足够了。此外,在我的情况下,有许多格式化字段根据输入计算它们的值,因此 multPercent 和 multNumber 计算值。我想确保所有输入都正确地转移到计算中。下面是一个带有工作 jsfiddle 的代码示例:

    <input data-bind="textInput:textPercent" />
    <div data-bind="text:multPercent"></div>
    <input data-bind="textInput:textNumber" />
    <div data-bind="text:multNumber"></div>
    

    以及随附的 javascript:

    function dataBindings() {
    var self = this;
    
    self.percent = function(str){
        var splice = str.toString().replace('%','');
        splice = splice + '%';
        return splice;
    };
    
    self.number = function(numStr){
        var formatted;
        if (Number(numStr) % 1) {
            var integer = numStr.toString().replace(/\.\d+/g,'');
            var decimal = numStr.toString().replace(/\d+\./g,'');
            integer = integer.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,"); //add comma formatting
            formatted = integer + '.' + decimal;
            console.log('formatted = '+formatted);
            return formatted;
        } else {
            formatted = numStr.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
            return formatted;
        }       
    };
    
    self.displayPercent = ko.observable('5%');
    self.rawPercent = ko.observable(5);
    self.formattedPercent = ko.computed({
        read: function() {
             return self.displayPercent();   
        },
        write: function(newValue) {
            if (newValue==='') {
                newValue = 0;
                self.rawPercent(0);
                var f = self.percent(newValue);
                self.displayPercent(f);
            } else {
                if (newValue.charAt(0)==='0') {
                    newValue = newValue.slice(1);
                }
                self.rawPercent(parseFloat(newValue.toString().replace('%','')));
                var f = self.percent(newValue);
                self.displayPercent(f);
            }
        }
    });
    
    self.displayNumber = ko.observable('3,000');
    self.rawNumber = ko.observable(3000);
    self.formattedNumber = ko.computed({
        read: function(){
            return self.displayNumber();
        },
        write: function(newValue) {
            if (newValue==='') {
                newValue = 0;
                self.rawNumber(0);
                self.displayNumber('0');
            } else {
                if (newValue.charAt(0)==='0') {
                   newValue = newValue.slice(1);
                }
                newValue = newValue.replace(/(,)+/g,'');
                self.rawNumber(parseFloat(newValue));
                var n = self.number(newValue);
                self.displayNumber(n);
            }
        }
    });
    
    self.multPercent = ko.computed(function(){
        return self.percent(self.rawPercent() * self.rawPercent());
    });
    
    self.multNumber = ko.computed(function(){
        return self.number(self.rawNumber() * self.rawNumber());
    });    
    
    return {
        textPercent: self.formattedPercent,
        multPercent: self.multPercent,
        textNumber: self.formattedNumber,
        multNumber: self.multNumber
    };
    }
    
    ko.applyBindings(new dataBindings());
    

    http://jsfiddle.net/jschevling/mwbzp55t/

    【讨论】:

      猜你喜欢
      • 2015-12-26
      • 2020-10-08
      • 1970-01-01
      • 1970-01-01
      • 2015-03-30
      • 2014-09-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多