8

看到工作 jsFiddle:http: //jsfiddle.net/ruslans/vFK82/

我有 3 个字段:净价(不含税)、税额和总价(不含增值税的价格 + 税额)。NetPrice 和 Total 是可写的,即您可以更改其中任何一个,而其他 2 个值必须自动计算。

我完成它的方式是使用 3 个可观察对象和 2 个计算剔除对象,但我认为也许更了解 Knockout 的人可以提出一种更有效的方法来实现这一点。

html:

Net Price:
<input type="textbox" data-bind="value: NetPriceCalc" />
<br />Tax Amount:
<label data-bind="html: TaxAmt"></label>
<br />Total:
<input type="textbox" data-bind="value: TotalCalc" />

脚本:

var viewModel = {
    NetPrice: ko.observable(100),
    TaxAmt: ko.observable(20),
    Total: ko.observable(120),
    TaxRate: 0.2
};

viewModel.updateTaxAmt = function (useNetPrice) {
    if (useNetPrice) {
        return this.TaxAmt(this.NetPrice() * this.TaxRate);
    } else {
        var total = Number(this.Total());
        var taxAmt = total - total / (1 + this.TaxRate);
        return this.TaxAmt(taxAmt);
    }
};
viewModel.updateNetPrice = function () {
    this.NetPrice(Number(this.Total()) - Number(this.TaxAmt()));
};
viewModel.updateTotal = function () {
    this.Total(Number(this.NetPrice()) + Number(this.TaxAmt()));
};

viewModel.NetPriceCalc = ko.computed({
    read: function () {
        console.log("NetPriceCalc read");
        return viewModel.NetPrice();
    },
    write: function (value) {
        console.log("NetPriceCalc write");
        viewModel.NetPrice(value);
        viewModel.updateTaxAmt(true);
        return viewModel.updateTotal();
    }
});
viewModel.TotalCalc = ko.computed({
    read: function () {
        console.log("TotalCalc read");
        return viewModel.Total();
    },
    write: function (value) {
        console.log("TotalCalc write");
        viewModel.Total(value);
        viewModel.updateTaxAmt(false);
        return viewModel.updateNetPrice();
    }
});

ko.applyBindings(viewModel);
4

3 回答 3

5

对 OP 的一些评论:

  • 您不需要. return_writeko.computed
  • 您的方法Number()在多个地方使用该功能,您可能希望更改它以获得特定的精度(或用于验证用户输入的某个集中位置)。所以你可以使用ko.extenders来改进它。我会特别推荐 ko 团队已经制作的扩展器,名为ko.extenders.numeric.
  • 您的方法也在console.log()多个地方使用,您可能希望使用 ko team 制作的另一个 ko.extender ko.extenders.logChange
  • 而不是ko.computed在这种情况下,我认为最好使用它,subscribe因为它需要更少的代码(并且可能更快)。

我的方法是这样的:

function viewModel() {
    this.TaxRate = 0.2;
    this.NetPrice = ko.observable().extend({ numeric: 2, logChange: "NetPrice"  });
    this.TaxAmt = ko.observable().extend({ numeric: 2, logChange: "TaxAmt"  });
    this.Total = ko.observable().extend({ numeric: 2, logChange: "Total"  });

    this.NetPrice.subscribe(function (newNetPrice) {
        this.TaxAmt(newNetPrice * this.TaxRate);
        this.Total(newNetPrice + this.TaxAmt());
    }, this);
    this.Total.subscribe(function (newTotal) {
        this.TaxAmt(newTotal - newTotal / (1 + this.TaxRate));
        this.NetPrice(newTotal - this.TaxAmt());
    }, this);

    this.NetPrice(100);
}

// then I have the extenders code copied exactly as seen in: http://knockoutjs.com/documentation/extenders.html)
ko.extenders.numeric = ...
ko.extenders.logChange = ... 

// and finally init everything as usual
ko.applyBindings(new viewModel());

你可以在这里看到工作小提琴:http: //jsfiddle.net/protron/JFPgu/2/

请注意,此解决方案中的数字永远不会比数字扩展器上指定的小数位数更多(即使用户输入的值也会自动固定为所需的精度)。

并将我的答案与 gaurav 目前接受的答案进行比较(这也非常好和简单):我认为我的方法的主要优点是它可以让你使用这些很棒的扩展器。

于 2013-07-19T19:12:37.663 回答
4

一个稍微更好和更有效的方法可能是这样的:

工作小提琴

html

Net Price:
<input type="textbox" data-bind="value: NetPrice" />
<br />Tax Amount:
<label data-bind="html: TaxAmt"></label>
<br />Total:
<input type="textbox" data-bind="value: Total" />

JS

function viewModel() {
    var self = this;

    self.NetPrice = ko.observable(100);

    self.TaxRate = 0.2;

    self.TaxAmt = ko.computed(function() {
        return parseFloat(self.NetPrice()) * self.TaxRate;
    });

    self.Total = ko.computed({
        read: function() { 
               return parseFloat(self.NetPrice()) + self.TaxAmt();
        },
        write: function(val){
                var total = parseFloat(val);
                var taxAmt = total - total / (1 + self.TaxRate);     
                self.NetPrice(total - taxAmt);
        }
    });
}

希望能帮助到你!

于 2013-04-10T11:37:59.187 回答
0

不能保证这会解决问题,但有时启用延迟更新可以解决此类问题。

这是一个需要注意的好特性,但在为已经工作的应用程序启用它时要谨慎——而且如果你确实有一个潜在的问题,那么你仍然需要修复它。

http://knockoutjs.com/documentation/deferred-updates.html

于 2017-04-07T19:55:32.793 回答