我想用JavaScript格式化价格。我想要一个函数,它将浮点作为参数,并返回如下格式的字符串:

"$ 2,500.00"

我该怎么做?


当前回答

请在下面的代码中找到我为支持国际化而开发的内容。

它将给定的数值格式化为特定于语言的格式。在给定的示例中,我使用了“en”,同时测试了“es”、“fr”和其他格式不同的国家。它不仅可以阻止用户键入字符,还可以格式化制表符上的值。

我已经为数字和十进制格式创建了组件。除此之外,我还创建了parseNumber(value,locale)和parseDecimal(value,locale)函数,这些函数将解析格式化数据以用于任何其他业务目的。所述函数将接受格式化数据并返回非格式化值。我在下面的共享代码中使用了jQuery验证器插件。

HTML格式:

<tr>
    <td>
        <label class="control-label">
            Number Field:
        </label>
        <div class="inner-addon right-addon">
            <input type="text" id="numberField"
                   name="numberField"
                   class="form-control"
                   autocomplete="off"
                   maxlength="17"
                   data-rule-required="true"
                   data-msg-required="Cannot be blank."
                   data-msg-maxlength="Exceeding the maximum limit of 13 digits. Example: 1234567890123"
                   data-rule-numberExceedsMaxLimit="en"
                   data-msg-numberExceedsMaxLimit="Exceeding the maximum limit of 13 digits. Example: 1234567890123"
                   onkeydown="return isNumber(event, 'en')"
                   onkeyup="return updateField(this)"
                   onblur="numberFormatter(this,
                               'en',
                               'Invalid character(s) found. Please enter valid characters.')">
        </div>
    </td>
</tr>

<tr>
    <td>
        <label class="control-label">
            Decimal Field:
        </label>
        <div class="inner-addon right-addon">
            <input type="text" id="decimalField"
                   name="decimalField"
                   class="form-control"
                   autocomplete="off"
                   maxlength="20"
                   data-rule-required="true"
                   data-msg-required="Cannot be blank."
                   data-msg-maxlength="Exceeding the maximum limit of 16 digits. Example: 1234567890123.00"
                   data-rule-decimalExceedsMaxLimit="en"
                   data-msg-decimalExceedsMaxLimit="Exceeding the maximum limit of 16 digits. Example: 1234567890123.00"
                   onkeydown="return isDecimal(event, 'en')"
                   onkeyup="return updateField(this)"
                   onblur="decimalFormatter(this,
                       'en',
                       'Invalid character(s) found. Please enter valid characters.')">
        </div>
    </td>
</tr>

JavaScript:

/*
 * @author: dinesh.lomte
 */
/* Holds the maximum limit of digits to be entered in number field. */
var numericMaxLimit = 13;
/* Holds the maximum limit of digits to be entered in decimal field. */
var decimalMaxLimit = 16;

/**
 *
 * @param {type} value
 * @param {type} locale
 * @returns {Boolean}
 */
parseDecimal = function(value, locale) {

    value = value.trim();
    if (isNull(value)) {
        return 0.00;
    }
    if (isNull(locale)) {
        return value;
    }
    if (getNumberFormat(locale)[0] === '.') {
        value = value.replace(/\./g, '');
    } else {
        value = value.replace(
                    new RegExp(getNumberFormat(locale)[0], 'g'), '');
    }
    if (getNumberFormat(locale)[1] === ',') {
        value = value.replace(
                    new RegExp(getNumberFormat(locale)[1], 'g'), '.');
    }
    return value;
};

/**
 *
 * @param {type} element
 * @param {type} locale
 * @param {type} nanMessage
 * @returns {Boolean}
 */
decimalFormatter = function (element, locale, nanMessage) {

    showErrorMessage(element.id, false, null);
    if (isNull(element.id) || isNull(element.value) || isNull(locale)) {
        return true;
    }
    var value = element.value.trim();
    value = value.replace(/\s/g, '');
    value = parseDecimal(value, locale);
    var numberFormatObj = new Intl.NumberFormat(locale,
            {   minimumFractionDigits: 2,
                maximumFractionDigits: 2
            }
    );
    if (numberFormatObj.format(value) === 'NaN') {
        showErrorMessage(element.id, true, nanMessage);
        setFocus(element.id);
        return false;
    }
    element.value = numberFormatObj.format(value);
    return true;
};

/**
 *
 * @param {type} element
 * @param {type} locale
 * @param {type} nanMessage
 * @returns {Boolean}
 */
numberFormatter = function (element, locale, nanMessage) {

    showErrorMessage(element.id, false, null);
    if (isNull(element.id) || isNull(element.value) || isNull(locale)) {
        return true;
    }
    var value = element.value.trim();
    var format = getNumberFormat(locale);
    if (hasDecimal(value, format[1])) {
        showErrorMessage(element.id, true, nanMessage);
        setFocus(element.id);
        return false;
    }
    value = value.replace(/\s/g, '');
    value = parseNumber(value, locale);
    var numberFormatObj = new Intl.NumberFormat(locale,
            {   minimumFractionDigits: 0,
                maximumFractionDigits: 0
            }
    );
    if (numberFormatObj.format(value) === 'NaN') {
        showErrorMessage(element.id, true, nanMessage);
        setFocus(element.id);
        return false;
    }
    element.value =
            numberFormatObj.format(value);
    return true;
};

/**
 *
 * @param {type} id
 * @param {type} flag
 * @param {type} message
 * @returns {undefined}
 */
showErrorMessage = function(id, flag, message) {

    if (flag) {
        // only add if not added
        if ($('#'+id).parent().next('.app-error-message').length === 0) {
            var errorTag = '<div class=\'app-error-message\'>' + message + '</div>';
            $('#'+id).parent().after(errorTag);
        }
    } else {
        // remove it
        $('#'+id).parent().next(".app-error-message").remove();
    }
};

/**
 *
 * @param {type} id
 * @returns
 */
setFocus = function(id) {

    id = id.trim();
    if (isNull(id)) {
        return;
    }
    setTimeout(function() {
        document.getElementById(id).focus();
    }, 10);
};

/**
 *
 * @param {type} value
 * @param {type} locale
 * @returns {Array}
 */
parseNumber = function(value, locale) {

    value = value.trim();
    if (isNull(value)) {
        return 0;
    }
    if (isNull(locale)) {
        return value;
    }
    if (getNumberFormat(locale)[0] === '.') {
        return value.replace(/\./g, '');
    }
    return value.replace(
        new RegExp(getNumberFormat(locale)[0], 'g'), '');
};

/**
 *
 * @param {type} locale
 * @returns {Array}
 */
getNumberFormat = function(locale) {

    var format = [];
    var numberFormatObj = new Intl.NumberFormat(locale,
            {   minimumFractionDigits: 2,
                maximumFractionDigits: 2
            }
    );
    var value = numberFormatObj.format('132617.07');
    format[0] = value.charAt(3);
    format[1] = value.charAt(7);
    return format;
};

/**
 *
 * @param {type} value
 * @param {type} fractionFormat
 * @returns {Boolean}
 */
hasDecimal = function(value, fractionFormat) {

    value = value.trim();
    if (isNull(value) || isNull(fractionFormat)) {
        return false;
    }
    if (value.indexOf(fractionFormat) >= 1) {
        return true;
    }
};

/**
 *
 * @param {type} event
 * @param {type} locale
 * @returns {Boolean}
 */
isNumber = function(event, locale) {

    var keyCode = event.which ? event.which : event.keyCode;
    // Validating if user has pressed shift character
    if (keyCode === 16) {
        return false;
    }
    if (isNumberKey(keyCode)) {
        return true;
    }
    var numberFormatter = [32, 110, 188, 190];
    if (keyCode === 32
            && isNull(getNumberFormat(locale)[0]) === isNull(getFormat(keyCode))) {
        return true;
    }
    if (numberFormatter.indexOf(keyCode) >= 0
            && getNumberFormat(locale)[0] === getFormat(keyCode)) {
        return true;
    }
    return false;
};

/**
 *
 * @param {type} event
 * @param {type} locale
 * @returns {Boolean}
 */
isDecimal = function(event, locale) {

    var keyCode = event.which ? event.which : event.keyCode;
    // Validating if user has pressed shift character
    if (keyCode === 16) {
        return false;
    }
    if (isNumberKey(keyCode)) {
        return true;
    }
    var numberFormatter = [32, 110, 188, 190];
    if (keyCode === 32
            && isNull(getNumberFormat(locale)[0]) === isNull(getFormat(keyCode))) {
        return true;
    }
    if (numberFormatter.indexOf(keyCode) >= 0
            && (getNumberFormat(locale)[0] === getFormat(keyCode)
                || getNumberFormat(locale)[1] === getFormat(keyCode))) {
        return true;
    }
    return false;
};

/**
 *
 * @param {type} keyCode
 * @returns {Boolean}
 */
isNumberKey = function(keyCode) {

    if ((keyCode >= 48 && keyCode <= 57) ||
        (keyCode >= 96 && keyCode <= 105)) {
        return true;
    }
    var keys = [8, 9, 13, 35, 36, 37, 39, 45, 46, 109, 144, 173, 189];
    if (keys.indexOf(keyCode) !== -1) {
        return true;
    }
    return false;
};

/**
 *
 * @param {type} keyCode
 * @returns {JSON@call;parse.numberFormatter.value|String}
 */
getFormat = function(keyCode) {

    var jsonString = '{"numberFormatter" : [{"key":"32", "value":" ", "description":"space"}, {"key":"188", "value":",", "description":"comma"}, {"key":"190", "value":".", "description":"dot"}, {"key":"110", "value":".", "description":"dot"}]}';
    var jsonObject = JSON.parse(jsonString);
    for (var key in jsonObject.numberFormatter) {
        if (jsonObject.numberFormatter.hasOwnProperty(key)
                && keyCode === parseInt(jsonObject.numberFormatter[key].key)) {
            return jsonObject.numberFormatter[key].value;
        }
    }
    return '';
};

/**
 *
 * @type String
 */
var jsonString = '{"shiftCharacterNumberMap" : [{"char":")", "number":"0"}, {"char":"!", "number":"1"}, {"char":"@", "number":"2"}, {"char":"#", "number":"3"}, {"char":"$", "number":"4"}, {"char":"%", "number":"5"}, {"char":"^", "number":"6"}, {"char":"&", "number":"7"}, {"char":"*", "number":"8"}, {"char":"(", "number":"9"}]}';

/**
 *
 * @param {type} value
 * @returns {JSON@call;parse.shiftCharacterNumberMap.number|String}
 */
getShiftCharSpecificNumber = function(value) {

    var jsonObject = JSON.parse(jsonString);
    for (var key in jsonObject.shiftCharacterNumberMap) {
        if (jsonObject.shiftCharacterNumberMap.hasOwnProperty(key)
                && value === jsonObject.shiftCharacterNumberMap[key].char) {
            return jsonObject.shiftCharacterNumberMap[key].number;
        }
    }
    return '';
};

/**
 *
 * @param {type} value
 * @returns {Boolean}
 */
isShiftSpecificChar = function(value) {

    var jsonObject = JSON.parse(jsonString);
    for (var key in jsonObject.shiftCharacterNumberMap) {
        if (jsonObject.shiftCharacterNumberMap.hasOwnProperty(key)
                && value === jsonObject.shiftCharacterNumberMap[key].char) {
            return true;
        }
    }
    return false;
};

/**
 *
 * @param {type} element
 * @returns {undefined}
 */
updateField = function(element) {

    var value = element.value;

    for (var index = 0; index < value.length; index++) {
        if (!isShiftSpecificChar(value.charAt(index))) {
            continue;
        }
        element.value = value.replace(
                value.charAt(index),
                getShiftCharSpecificNumber(value.charAt(index)));
    }
};

/**
 *
 * @param {type} value
 * @param {type} element
 * @param {type} params
 */
jQuery.validator.addMethod('numberExceedsMaxLimit', function(value, element, params) {

    value = parseInt(parseNumber(value, params));
    if (value.toString().length > numericMaxLimit) {
        showErrorMessage(element.id, false, null);
        setFocus(element.id);
        return false;
    }
    return true;
}, 'Exceeding the maximum limit of 13 digits. Example: 1234567890123.');

/**
 *
 * @param {type} value
 * @param {type} element
 * @param {type} params
 */
jQuery.validator.addMethod('decimalExceedsMaxLimit', function(value, element, params) {

    value = parseFloat(parseDecimal(value, params)).toFixed(2);
    if (value.toString().substring(
            0, value.toString().lastIndexOf('.')).length > numericMaxLimit
            || value.toString().length > decimalMaxLimit) {
        showErrorMessage(element.id, false, null);
        setFocus(element.id);
        return false;
    }
    return true;
}, 'Exceeding the maximum limit of 16 digits. Example: 1234567890123.00.');

/**
 * @param {type} id
 * @param {type} locale
 * @returns {boolean}
 */
isNumberExceedMaxLimit = function(id, locale) {

    var value = parseInt(parseNumber(
            document.getElementById(id).value, locale));
    if (value.toString().length > numericMaxLimit) {
        setFocus(id);
        return true;
    }
    return false;
};

/**
 * @param {type} id
 * @param {type} locale
 * @returns {boolean}
 */
isDecimalExceedsMaxLimit = function(id, locale) {

    var value = parseFloat(parseDecimal(
            document.getElementById(id).value, locale)).toFixed(2);
    if (value.toString().substring(
            0, value.toString().lastIndexOf('.')).length > numericMaxLimit
            || value.toString().length > decimalMaxLimit) {
        setFocus(id);
        return true;
    }
    return false;
};

其他回答

这可能有点晚了,但这是我刚刚为同事准备的一个方法,可以为所有数字添加一个支持区域设置的.toCurrencyString()函数。内部化仅用于数字分组,而不是货币符号-如果您输出美元,请使用提供的“$”,因为日本或中国的123 4567美元与美国的1234567美元相同。如果您输出欧元等,请将货币符号从“$”改为“$”。

在HTML<head>部分的任何地方或在需要使用它之前的任何地方声明:

  Number.prototype.toCurrencyString = function(prefix, suffix) {
    if (typeof prefix === 'undefined') { prefix = '$'; }
    if (typeof suffix === 'undefined') { suffix = ''; }
    var _localeBug = new RegExp((1).toLocaleString().replace(/^1/, '').replace(/\./, '\\.') + "$");
    return prefix + (~~this).toLocaleString().replace(_localeBug, '') + (this % 1).toFixed(2).toLocaleString().replace(/^[+-]?0+/,'') + suffix;
  }

那你就完了!在需要将数字输出为货币的任何位置使用(number).toCurrencyString()。

var MyNumber = 123456789.125;
alert(MyNumber.toCurrencyString()); // alerts "$123,456,789.13"
MyNumber = -123.567;
alert(MyNumber.toCurrencyString()); // alerts "$-123.57"

http://code.google.com/p/javascript-number-formatter/:

短、快、灵活但独立。只有75行,包括MIT许可证信息、空白行和注释。接受标准数字格式,如#、##0.00或带否定的-000.####。接受任何国家/地区格式,如###0,00,#,###.##,#‘###.##或任何类型的非编号符号。接受任意数字分组。#、##、#0.000或#、####0.##均有效。接受任何冗余/防傻瓜格式。##、###、##。#或0#、#00####0#都正常。自动数字舍入。简单的界面,只需提供如下掩码和值:格式(“0.0000”,3.141592)

UPDATE这是我自己开发的应用程序,用于最常见的任务:

var NumUtil = {};

/**
  Petty print 'num' wth exactly 'signif' digits.
  pp(123.45, 2) == "120"
  pp(0.012343, 3) == "0.0123"
  pp(1.2, 3) == "1.20"
*/
NumUtil.pp = function(num, signif) {
    if (typeof(num) !== "number")
        throw 'NumUtil.pp: num is not a number!';
    if (isNaN(num))
        throw 'NumUtil.pp: num is NaN!';
    if (num < 1e-15 || num > 1e15)
        return num;
    var r = Math.log(num)/Math.LN10;
    var dot = Math.floor(r) - (signif-1);
    r = r - Math.floor(r) + (signif-1);
    r = Math.round(Math.exp(r * Math.LN10)).toString();
    if (dot >= 0) {
        for (; dot > 0; dot -= 1)
            r += "0";
        return r;
    } else if (-dot >= r.length) {
        var p = "0.";
        for (; -dot > r.length; dot += 1) {
            p += "0";
        }
        return p+r;
    } else {
        return r.substring(0, r.length + dot) + "." + r.substring(r.length + dot);
    }
}

/** Append leading zeros up to 2 digits. */
NumUtil.align2 = function(v) {
    if (v < 10)
        return "0"+v;
    return ""+v;
}
/** Append leading zeros up to 3 digits. */
NumUtil.align3 = function(v) {
    if (v < 10)
        return "00"+v;
    else if (v < 100)
        return "0"+v;
    return ""+v;
}

NumUtil.integer = {};

/** Round to integer and group by 3 digits. */
NumUtil.integer.pp = function(num) {
    if (typeof(num) !== "number") {
        console.log("%s", new Error().stack);
        throw 'NumUtil.integer.pp: num is not a number!';
    }
    if (isNaN(num))
        throw 'NumUtil.integer.pp: num is NaN!';
    if (num > 1e15)
        return num;
    if (num < 0)
        throw 'Negative num!';
    num = Math.round(num);
    var group = num % 1000;
    var integ = Math.floor(num / 1000);
    if (integ === 0) {
        return group;
    }
    num = NumUtil.align3(group);
    while (true) {
        group = integ % 1000;
        integ = Math.floor(integ / 1000);
        if (integ === 0)
            return group + " " + num;
        num = NumUtil.align3(group) + " " + num;
    }
    return num;
}

NumUtil.currency = {};

/** Round to coins and group by 3 digits. */
NumUtil.currency.pp = function(amount) {
    if (typeof(amount) !== "number")
        throw 'NumUtil.currency.pp: amount is not a number!';
    if (isNaN(amount))
        throw 'NumUtil.currency.pp: amount is NaN!';
    if (amount > 1e15)
        return amount;
    if (amount < 0)
        throw 'Negative amount!';
    if (amount < 1e-2)
        return 0;
    var v = Math.round(amount*100);
    var integ = Math.floor(v / 100);
    var frac = NumUtil.align2(v % 100);
    var group = integ % 1000;
    integ = Math.floor(integ / 1000);
    if (integ === 0) {
        return group + "." + frac;
    }
    amount = NumUtil.align3(group);
    while (true) {
        group = integ % 1000;
        integ = Math.floor(integ / 1000);
        if (integ === 0)
            return group + " " + amount + "." + frac;
        amount = NumUtil.align3(group) + " " + amount;
    }
    return amount;
}
function CurrencyFormatted(amount)
{
    var i = parseFloat(amount);
    if(isNaN(i)) { i = 0.00; }
    var minus = '';
    if(i < 0) { minus = '-'; }
    i = Math.abs(i);
    i = parseInt((i + .005) * 100);
    i = i / 100;
    s = new String(i);
    if(s.indexOf('.') < 0) { s += '.00'; }
    if(s.indexOf('.') == (s.length - 2)) { s += '0'; }
    s = minus + s;
    return s;
}

来自WillMaster。

快速快捷的解决方案(适用于任何地方!)

(12345.67).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');  // 12,345.67

此解决方案背后的思想是用第一个匹配和逗号替换匹配的部分,即“$&,”。匹配是使用前瞻方法完成的。您可以将表达式读为“匹配一个数字,如果它后面跟着三个数字集(一个或多个)和一个点的序列”。

测验:

1        --> "1.00"
12       --> "12.00"
123      --> "123.00"
1234     --> "1,234.00"
12345    --> "12,345.00"
123456   --> "123,456.00"
1234567  --> "1,234,567.00"
12345.67 --> "12,345.67"

演示:http://jsfiddle.net/hAfMM/9571/


扩展短解决方案

您还可以扩展Number对象的原型,以添加对任意数量的小数[0..n]和数字组大小[0..x]的额外支持:

/**
 * Number.prototype.format(n, x)
 * 
 * @param integer n: length of decimal
 * @param integer x: length of sections
 */
Number.prototype.format = function(n, x) {
    var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\.' : '$') + ')';
    return this.toFixed(Math.max(0, ~~n)).replace(new RegExp(re, 'g'), '$&,');
};

1234..format();           // "1,234"
12345..format(2);         // "12,345.00"
123456.7.format(3, 2);    // "12,34,56.700"
123456.789.format(2, 4);  // "12,3456.79"

演示/测试:http://jsfiddle.net/hAfMM/435/


超扩展短解决方案

在此超级扩展版本中,您可以设置不同的分隔符类型:

/**
 * Number.prototype.format(n, x, s, c)
 * 
 * @param integer n: length of decimal
 * @param integer x: length of whole part
 * @param mixed   s: sections delimiter
 * @param mixed   c: decimal delimiter
 */
Number.prototype.format = function(n, x, s, c) {
    var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\D' : '$') + ')',
        num = this.toFixed(Math.max(0, ~~n));

    return (c ? num.replace('.', c) : num).replace(new RegExp(re, 'g'), '$&' + (s || ','));
};

12345678.9.format(2, 3, '.', ',');  // "12.345.678,90"
123456.789.format(4, 4, ' ', ':');  // "12 3456:7890"
12345678.9.format(0, 3, '-');       // "12-345-679"

演示/测试:http://jsfiddle.net/hAfMM/612/

String.prototype.toPrice = function () {
    var v;
    if (/^\d+(,\d+)$/.test(this))
        v = this.replace(/,/, '.');
    else if (/^\d+((,\d{3})*(\.\d+)?)?$/.test(this))
        v = this.replace(/,/g, "");
    else if (/^\d+((.\d{3})*(,\d+)?)?$/.test(this))
        v = this.replace(/\./g, "").replace(/,/, ".");
    var x = parseFloat(v).toFixed(2).toString().split("."),
    x1 = x[0],
    x2 = ((x.length == 2) ? "." + x[1] : ".00"),
    exp = /^([0-9]+)(\d{3})/;
    while (exp.test(x1))
        x1 = x1.replace(exp, "$1" + "," + "$2");
    return x1 + x2;
}

alert("123123".toPrice()); //123,123.00
alert("123123,316".toPrice()); //123,123.32
alert("12,312,313.33213".toPrice()); //12,312,313.33
alert("123.312.321,32132".toPrice()); //123,312,321.32