0

我想在 knockout.js 中解决以下问题:我有三个输入;price,quantitytotal, 我想设置的地方

 total = price * quantity 

当我更新priceor quantity,但我也想设置

 price = total / quantity 

如果我更新total.

我最初是用一个计算的 observable 来做这个的,但是这几乎是有效的,但是我在舍入时遇到了问题。例如,如果我这样做

quantity(3)
total(100)

我想price设置为 33.33,只有两位小数,而total仍应设置为 100,因此身份total = price * quantity不太成立。

在我采用的计算可观察方法中,total在这种情况下将设置为 99.99。这就是使这种情况与 docs 中的 fullname/firstname/lastname 示例不同的原因

本质上price/total字段是相互递归的。除了手动订阅之外,我找不到解决这个问题的好方法,但这感觉很不习惯,这意味着我必须手动处理一堆订阅等。

4

2 回答 2

3

我通过制作“真实价值”ko.observables(即数量、价格和总计)、跟踪表单字段上的焦点事件以及使用 ko.computed() 重新计算(但如果当前字段被选中)并格式化表单的值。

一句话描述听起来很复杂,但在代码方面并没有那么复杂。

JavaScript:

var Model = function () {
    var self = this;

    self.quantity = ko.observable(0);
    self.price = ko.observable(0);
    self.price.selected = ko.observable(false);
    self.total = ko.observable(0);
    self.total.selected = ko.observable(false);

    self.formattedPrice = ko.computed({
        read: function () {
            if (!self.price.selected()) {
                 var total = self.total() || 0;
                 var quantity = self.quantity() || 0;
                 var value = total / quantity;
                 self.price(isNaN(value) ? 0 : value);
            }
            return '$' + self.price().toFixed(2);
        },
        write: function (value) {
            value = parseFloat(value.replace(/[^\.\d]/g, ""));
            self.price(isNaN(value) ? 0 : value);
        }
    });

    self.formattedTotal = ko.computed({
        read: function () {
            if (!self.total.selected()) {
                var quantity = self.quantity() || 0;
                var price = self.price() || 0;
                var value = quantity * price;
                self.total(isNaN(value) ? 0 : value);
            }
            return '$' + self.total().toFixed(2);
        }, 
        write: function (value) {
            value = parseFloat(value.replace(/[^\.\d]/g, ""));
            self.total(isNaN(value) ? 0 : value);
        }
    });
};

ko.applyBindings(new Model());

在 HTML 中,您可以像这样绑定价格和总计:

<input data-bind="value: formattedPrice, hasfocus: price.selected" />

<input data-bind="value: formattedTotal, hasfocus: total.selected" />

如果您想查看一个工作示例,请在jsfiddle 编写代码。

于 2013-06-06T18:28:35.440 回答
0

感谢你的回答。仅供参考,这是我目前拥有的解决方案,除非它给我带来问题,否则可能会坚持下去。

    var self = this;
    this.price = ko.observable().extend({numeric: 2});
    this.quantity = ko.observable(1).extend({ numeric: 2 });
    this.total = ko.observable(1).extend({ numeric: 2 });

    var unsub_total = this.total.subscribe(function (total) {
        if (self.quantity() != 0)
            self.price(total / self.quantity())
    });

    // setting quantity will update both price and total
    var unsub_qty = this.quantity.subscribe(function (qty) {
        self.total(self.price() * qty);
    });

    var unsub_price = this.price.subscribe(function (price) {
        self.total(price * self.quantity());
    });

    this.unsub = function() { unsub_total(); unsub_price(); unsub_qty(); };
于 2013-06-08T21:07:23.747 回答