如何在 Vue 组件中格式化货币?

我的 Vue 组件是这样的:

<template>
<div>
<div class="panel-group"v-for="item in list">
<div class="col-md-8">
<small>
Total: <b>{{ item.total }}</b>
</small>
</div>
</div>
</div>
</template>


<script>
export default {
...
computed: {
list: function() {
return this.$store.state.transaction.list
},
...
}
}
</script>

{{ item.total }}的结果是

26000000

但是我想把它设计成这样:

26.000.000.00

在 jquery 或 javascript 中,我可以这样做

但是,如何做到这一点,在价值组成部分?

151378 次浏览

UPDATE: I suggest using a solution with filters, provided by @Jess.

I would write a method for that, and then where you need to format price you can just put the method in the template and pass value down

methods: {
formatPrice(value) {
let val = (value/1).toFixed(2).replace('.', ',')
return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".")
}
}

And then in template:

<template>
<div>
<div class="panel-group"v-for="item in list">
<div class="col-md-8">
<small>
Total: <b>\{\{ formatPrice(item.total) }}</b>
</small>
</div>
</div>
</div>
</template>

BTW - I didn't put too much care on replacing and regular expression. It could be improved.enter code here

Vue.filter('tableCurrency', num => {
if (!num) {
return '0.00';
}
const number = (num / 1).toFixed(2).replace(',', '.');
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
});

The comment by @RoyJ has a great suggestion. In the template you can just use built-in localized strings:

<small>
Total: <b>\{\{ item.total.toLocaleString() }}</b>
</small>

It's not supported in some of the older browsers, but if you're targeting IE 11 and later, you should be fine.

There is issues with the precision of the accepted answer.

the round(value, decimals) function in this test works. unlike the simple toFixed example.

this is a test of the toFixed vs round method.

http://www.jacklmoore.com/notes/rounding-in-javascript/

  Number.prototype.format = function(n) {
return this.toFixed(Math.max(0, ~~n));
};
function round(value, decimals) {
return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}


// can anyone tell me why these are equivalent for  50.005, and 1050.005 through 8150.005 (increments of 50)


var round_to = 2;
var maxInt = 1500000;
var equalRound = '<h1>BEGIN HERE</h1><div class="matches">';
var increment = 50;
var round_from = 0.005;
var expected = 0.01;
var lastWasMatch = true;


for( var n = 0; n < maxInt; n=n+increment){
var data = {};
var numberCheck = parseFloat(n + round_from);
data.original = numberCheck * 1;
data.expected =  Number(n + expected) * 1;
data.formatIt = Number(numberCheck).format(round_to) * 1;
data.roundIt = round(numberCheck, round_to).toFixed(round_to) * 1;
data.numberIt = Number(numberCheck).toFixed(round_to) * 1;
//console.log(data);


if( data.roundIt !== data.formatIt || data.formatIt !== data.numberIt ||
data.roundIt !== data.numberIt || data.roundIt != data.expected
){
if(lastWasMatch){
equalRound = equalRound + '</div><div class="errors"> <hr/> Did Not Round UP <hr/>' ;
document.write(' <h3>EXAMPLE: Did Not Round UP: ' + numberCheck + '</h3><br /><hr/> ');
document.write('expected: '+data.expected + ' :: ' + (typeof data.expected)  + '<br />');
document.write('format: '+data.formatIt + ' :: ' + (typeof data.formatIt)  + '<br />');
document.write('round : '+data.roundIt + ' :: ' + (typeof data.roundIt)  + '<br />');
document.write('number: '+data.numberIt + ' :: ' + (typeof data.numberIt)  + '<br />');
lastWasMatch=false;
}
equalRound = equalRound + ', ' + numberCheck;
} else {
if(!lastWasMatch){
equalRound = equalRound + '</div><div class="matches"> <hr/> All Rounded UP! <hr/>' ;
} {
lastWasMatch=true;
}
equalRound = equalRound + ', ' + numberCheck;
}
}
document.write('equalRound: '+equalRound + '</div><br />');

mixin example

  export default {
methods: {
roundFormat: function (value, decimals) {
return Number(Math.round(value+'e'+decimals)+'e-'+decimals).toFixed(decimals);
},
currencyFormat: function (value, decimals, symbol='$') {
return symbol + this.roundFormat(value,2);
}
}
}

You can format currency writing your own code but it is just solution for the moment - when your app will grow you can need other currencies.

There is another issue with this:

  1. For EN-us - dolar sign is always before currency - $2.00,
  2. For selected PL you return sign after amount like 2,00 zł.

I think the best option is use complex solution for internationalization e.g. library vue-i18n( http://kazupon.github.io/vue-i18n/).

I use this plugin and I don't have to worry about such a things. Please look at documentation - it is really simple:

http://kazupon.github.io/vue-i18n/guide/number.html

so you just use:

<div id="app">
<p>\{\{ $n(100, 'currency') }}</p>
</div>

and set EN-us to get $100.00:

<div id="app">
<p>$100.00</p>
</div>

or set PL to get 100,00 zł:

<div id="app">
<p>100,00 zł</p>
</div>

This plugin also provide different features like translations and date formatting.

I have created a filter. The filter can be used in any page.

Vue.filter('toCurrency', function (value) {
if (typeof value !== "number") {
return value;
}
var formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
return formatter.format(value);
});

Then I can use this filter like this:

        <td class="text-right">
\{\{ invoice.fees | toCurrency }}
</td>

I used these related answers to help with the implementation of the filter:

With vuejs 2, you could use vue2-filters which does have other goodies as well.

npm install vue2-filters




import Vue from 'vue'
import Vue2Filters from 'vue2-filters'


Vue.use(Vue2Filters)

Then use it like so:

\{\{ amount | currency }} // 12345 => $12,345.00

Ref: https://www.npmjs.com/package/vue2-filters

I used the custom filter solution proposed by @Jess but in my project we are using Vue together with TypeScript. This is how it looks like with TypeScript and class decorators:

import Component from 'vue-class-component';
import { Filter } from 'vue-class-decorator';


@Component
export default class Home extends Vue {


@Filter('toCurrency')
private toCurrency(value: number): string {
if (isNaN(value)) {
return '';
}


var formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0
});
return formatter.format(value);
}
}

In this example the filter can only be used inside the component. I haven't tried to implement it as a global filter, yet.

You can use this example

formatPrice(value) {
return value.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
},

Try this:

methods: {
formatPrice(value) {
var formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'PHP',
minimumFractionDigits: 2
});
return formatter.format(value);
},
}

Then you can just call this like:

\{\{ formatPrice(item.total) }}

numeral.js is a JavaScript library for formatting and manipulating numbers.

You can format a currency so easily using it.

For example,

// price = 1200
{numeral(price).format(`$0,0.00`)}


// result $1,200.00

Here's the documentation. http://numeraljs.com/

You can make a filter that works on a project completely. You can also control the number of zeros after the sorter

in main.js create filter like this

Vue.filter("formatNumber", function (value) {
let val = (value / 1).toFixed(2).replace(".", ",");
return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
});

<template>
<div>
<div class="panel-group"v-for="item in list">
<div class="col-md-8">
<small>
Total: <b>\{\{ item.total | formatNumber }}</b>
</small>
</div>
</div>
</div>
</template>