KnockoutJS中的数字格式规则

我有一个有很多小数位的数字视图模型。 如果我的绑定是这样的:

<tr> <td data-bind="text: Date"></td> <td data-bind="text: ActualWeight"></td> <td data-bind="text: TrendWeight"></td> </tr> 

那么,当然,输出具有所有的小数位,是非常不可读的。 改变绑定看起来像这样解决了这个问题,但是非常冗长和“嘈杂”:

  <tr> <td data-bind="text: Date"></td> <td data-bind="text: ActualWeight().toFixed(1)"></td> <td data-bind="text: TrendWeight().toFixed(1)"></td> </tr> 

请注意,这是一个小的片段,不得不添加.toFixed(1)我绑定一个数字的每个地方导致比这里显示的更加凌乱的标记。

除了数字之外的所有东西,覆盖toString一直是我控制输出结果的一个有效方法。 任何build议的方式来告诉淘汰赛一次,在我的网页的一些中心方式之前,将数字转换为string之前,他们被添加到输出?

对于这个问题,有一个通用的方式来告诉淘汰赛如何格式化任何types的值似乎是有用的。 重写Date.prototype.toString的作品,但感觉有点沉重,因为它可能会影响其他使用.toString除了淘汰赛的。

有几种方法可以处理像这样的情况。 您可以select通过绑定来解决它,也可以将其推送到视图模型中。

如果您的视图模型是由映射插件创build的,并且您不想自定义其创build方式,那么可以考虑使用自定义绑定,该绑定是文本绑定的包装来处理格式。

像( http://jsfiddle.net/rniemeyer/RVL6q/ ):

 ko.bindingHandlers.numericText = { update: function(element, valueAccessor, allBindingsAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()), precision = ko.utils.unwrapObservable(allBindingsAccessor().precision) || ko.bindingHandlers.numericText.defaultPrecision, formattedValue = value.toFixed(precision); ko.bindingHandlers.text.update(element, function() { return formattedValue; }); }, defaultPrecision: 1 }; 

当然可以创build一个更通用的绑定(formattedText),它检查值并使用一些可重写的默认值对其进行格式化,或者允许您传入某些格式选项( { type: "numeric", precision: 2 } )。

对于你的情况,这听起来像第一个选项可能是一个不错的select。 然而,如果你想把它推入你的视图模型,那么你可以创build一个特殊的observable,它可以返回值的格式化版本和原始版本。

它可能是像( http://jsfiddle.net/rniemeyer/fetBG/ ):

 function formattedNumericObservable(initialValue, precision) { var _raw = ko.observable(initialValue), precision = precision || formattedNumericObservable.defaultPrecision, //the dependentObservable that we will return result = ko.dependentObservable({ read: function() { return _raw().toFixed(precision); }, write: _raw }); //expose raw value for binding result.raw = _raw; return result; } 

现在你可以根据你的需要绑定myValuemyValue.raw 。 否则,您可以翻转它并默认返回原始值,并显示formatted dependentObservable。 当像这样的对象被转换成JSON时,它将会丢失任何“子可观察对象”,所以如果你将这些数据发送回服务器,可能是一个考虑因素。

您可以再次使它更通用,并创build一个formattedObservable ,它接收有关如何格式化对象的一些信息。

最后,1.3 beta提供了一个extenders API。 你可以像上面这样做:( http://jsfiddle.net/rniemeyer/AsdES/

 ko.extenders.numeric = function(target, precision) { var result = ko.dependentObservable({ read: function() { return target().toFixed(precision); }, write: target }); result.raw = target; return result; }; 

然后,将其应用于如下所示的可观察对象: var myValue = ko.observable(1.223123).extend({numeric: 1});

您可以让扩展器只添加一个formatted dependentObservable,而不是返回dependentObservable本身。

由于淘汰赛现在支持扩展 ,我会使用它们,而不是自定义绑定。 绑定看起来像这样:

 <tr> <td data-bind="text: Date.extend({format : 'date'})"></td> <td data-bind="text: ActualWeight.extend({format : 'weight'})"></td> <td data-bind="text: TrendWeight.extend({format : 'weight'})"></td> </tr> 

在这种情况下,您必须编写format扩展器。 敲除文档中提供了示例。

格式化货币和百分比我创build了我的自定义绑定的数字格式.js,用于在http://adamwdraper.github.com/Numeral-js/上find的numer.min.js。;

numerformat.js(受dateformat.js和moment.min.js的启发)

 var formatNumber = function (element, valueAccessor, allBindingsAccessor, format) { // Provide a custom text value var value = valueAccessor(), allBindings = allBindingsAccessor(); var numeralFormat = allBindingsAccessor.numeralFormat || format; var strNumber = ko.utils.unwrapObservable(value); if (strNumber) { return numeral(strNumber).format(numeralFormat); } return ''; }; ko.bindingHandlers.numeraltext = { init: function (element, valueAccessor, allBindingsAccessor) { $(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)")); }, update: function (element, valueAccessor, allBindingsAccessor) { $(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)")); } }; ko.bindingHandlers.numeralvalue = { init: function (element, valueAccessor, allBindingsAccessor) { $(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)")); //handle the field changing ko.utils.registerEventHandler(element, "change", function () { var observable = valueAccessor(); observable($(element).val()); }); }, update: function (element, valueAccessor, allBindingsAccessor) { $(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)")); } }; ko.bindingHandlers.percenttext = { init: function (element, valueAccessor, allBindingsAccessor) { $(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)")); }, update: function (element, valueAccessor, allBindingsAccessor) { $(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)")); } }; ko.bindingHandlers.percentvalue = { init: function (element, valueAccessor, allBindingsAccessor) { $(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)")); //handle the field changing ko.utils.registerEventHandler(element, "change", function () { var observable = valueAccessor(); observable($(element).val()); }); }, update: function (element, valueAccessor, allBindingsAccessor) { $(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)")); } }; 

View中绑定的示例。

  <td><label>Available Commitment Balance:</label> </td> <td> <!-- ko with: SelectedLoan --> <span data-bind="numeraltext: AvailableCommitmentAmount"></span> <!-- /ko --> </td> <td><label> % Interest Rate:</label></td> <td> <!-- ko with: SelectedLoan --> <input data-bind="percentvalue: InterestRatePercent" /> <!-- /ko --> </td> <td><label> $ Amount To Transfer:</label></td> <td> <!-- ko with: SelectedLoan --> <input class="inputsmall" data-bind="numeralvalue: FundsHeldTotalAmount" /> <!-- /ko --> </td> 

build立在上面接受的答案。 我分叉RP Niemeyers小提琴以及添加逗号格式。 所以,如果你有10001.232这将格式为10,001.232。 如果你正在处理价格,这很重要。 再次,这只是build立在答案上。

的jsfiddle

 <div data-bind="numericText: myValue"></div> <div data-bind="numericText: myValue, positions: 3"></div> <div data-bind="numericText: myValue, positions: myPositions"></div> <input data-bind="value: myPositions" /> <div> <br> just testing commas<br> <input type=text id="withComma" readonly/> </div> 
 ko.bindingHandlers.numericText = { update: function(element, valueAccessor, allBindingsAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()); var positions= ko.utils.unwrapObservable(allBindingsAccessor().positions) || ko.bindingHandlers.numericText.defaultPositions; var formattedValue = value.toFixed(positions); var finalFormatted = ko.bindingHandlers.numericText.withCommas(formattedValue); ko.bindingHandlers.text.update(element, function() { return finalFormatted ; }); }, defaultPositions: 2, withCommas: function(original){ original+= ''; x = original.split('.'); x1 = x[0]; x2 = x.length > 1 ? '.' + x[1] : ''; var rgx = /(\d+)(\d{3})/; while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + ',' + '$2'); } return x1 + x2; } }; var viewModel = { myValue: ko.observable(12673.554), myPositions: ko.observable(4) }; ko.applyBindings(viewModel); /*Just testing the function below, you don't need thsi....*/ function addCommas(nStr) { nStr += ''; x = nStr.split('.'); x1 = x[0]; x2 = x.length > 1 ? '.' + x[1] : ''; var rgx = /(\d+)(\d{3})/; while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + ',' + '$2'); } return x1 + x2; } var formatted = addCommas('1070781.493') $('#withComma').val(formatted); 

我接触到使用jQuery Globalize插件的格式。 这是我的版本的格式处理程序, textFormattedvalueFormatted分别是文本和值绑定的包装。

用法将是:

 <span data-bind="textFormatted: Amount, pattern: 'n'" /> 

也可以指定文化。 但我认为这种控制不应该属于HTML,虽然它可以在开发或debugging时有帮助。

 <input data-bind="valueFormatted: Amount, pattern: 'n', culture: 'et'" type="text" /> 

pattern属性/绑定的值必须是Globalize.format( value, format, [locale] )函数的format参数所需的任何合适格式。 将在可选locale参数中使用的culture属性/绑定也一样。 全球化参考。

绑定定义:

 (function() { function getFormatedOrPlainResult(value, allBindingsAccessor) { var pattern = allBindingsAccessor.get('pattern'); if (pattern == null || !/\S*/.test(pattern)) { return value; } var valueToFormat = pattern === 'd' ? new Date(value) : value; return Globalize.format(valueToFormat, pattern, allBindingsAccessor.get('culture')); }; ko.bindingHandlers.textFormatted = { init: ko.bindingHandlers.text.init, update: function(element, valueAccessor, allBindingsAccessor) { var result = getFormatedOrPlainResult(ko.unwrap(valueAccessor()), allBindingsAccessor); ko.bindingHandlers.text.update(element, function() { return result; }); } }; ko.bindingHandlers.valueFormatted = { init: function(element, valueAccessor, allBindingsAccessor) { var result = getFormatedOrPlainResult(ko.unwrap(valueAccessor()), allBindingsAccessor); ko.bindingHandlers.value.init(element, function() { return result; }, allBindingsAccessor); }, update: function(element, valueAccessor, allBindingsAccessor) { var result = getFormatedOrPlainResult(ko.unwrap(valueAccessor()), allBindingsAccessor); ko.bindingHandlers.value.update(element, function() { return result; }, allBindingsAccessor); } }; }());