¿Cómo puedo formatear monedas en un componente de Vue?

81

Mi componente de Vue es así:

<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>

El resultado de {{ item.total }}es

26000000

Pero quiero formatearlo para que sea así:

26.000.000,00

En jquery o javascript, puedo hacerlo

Pero, ¿cómo hacerlo en el componente vue?

samuel toh
fuente
1
Si puede hacerlo en javascript para que pueda hacerlo en Vue ... use propiedades calculadas y devuelva el código javascript.
Happyriwan

Respuestas:

82

ACTUALIZACIÓN: sugiero usar una solución con filtros, proporcionada por @Jess.

Escribiría un método para eso, y luego, cuando necesite formatear el precio, puede simplemente poner el método en la plantilla y pasar el valor

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

Y luego en plantilla:

<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>

Por cierto, no puse demasiado cuidado en reemplazar y en expresiones regulares. Podría mejorarse.enter code here

Belmin Bedak
fuente
11
Consulte también developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… para conocer el formato de moneda localizada incorporado.
Roy J
@RoyJ Buena captura. Acabo de copiar la expresión regular de un proyecto anterior, básicamente, podía devolver el valor del método como quisiera.
Belmin Bedak
@BelminBedak ¿en qué piensas return (value/1).toFixed(2).toLocalString();?
retrovertigo
Funciona, pero reemplaza todos los decimales con comas
Dylan Glockler
¿Por qué no usar computeden su lugar?
localhost
183

He creado un filtro. El filtro se puede utilizar en cualquier página.

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

Entonces puedo usar este filtro así:

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

Usé estas respuestas relacionadas para ayudar con la implementación del filtro:

Cadena
fuente
5
¡Mi hombre! Ni siquiera sabía que podías hacer esto. Gracias resolvió mi problema de moneda y limpió mis mixins ya que la mayoría de ellos estaban haciendo este tipo de cosas.
Ominus
1
esta es la respuesta correcta
ierdna
No Intltiene el mejor apoyo .
Илья Зеленько
1
¿Qué tal en isNaN(parseFloat(value))lugar de typeof value !== "number"?
RonnyKnoxville
@JackalopeZero: Sí, es un mejor control. Trabajó en mi caso.
dotNET
22

Con vuejs 2, puede usar filtros vue2 que también tienen otras ventajas.

npm install vue2-filters


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

Vue.use(Vue2Filters)

Entonces úsalo así:

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

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

Yao Liu
fuente
10

Puede formatear la moneda escribiendo su propio código, pero es solo una solución por el momento: cuando su aplicación crezca, puede necesitar otras monedas.

Hay otro problema con esto:

  1. Para EN-us: el signo del dólar siempre está antes de la moneda: $ 2.00,
  2. Para PL seleccionado, devuelve el signo después de la cantidad como 2,00 EUR.

Creo que la mejor opción es utilizar una solución compleja para la internacionalización, por ejemplo, la biblioteca vue-i18n ( http://kazupon.github.io/vue-i18n/ ).

Utilizo este complemento y no tengo que preocuparme por esas cosas. Mire la documentación, es realmente simple:

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

así que solo usa:

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

y configure EN-us para obtener $ 100.00 :

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

o configure PL para obtener 100,00 zł :

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

Este complemento también proporciona diferentes características como traducciones y formato de fecha.

Arkowsky
fuente
8

El comentario de @RoyJ tiene una gran sugerencia. En la plantilla, puede usar cadenas localizadas integradas:

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

No es compatible con algunos de los navegadores más antiguos, pero si está apuntando a IE 11 y posterior, debería estar bien.

AaronBaker
fuente
Así de simple. Confirmado que funciona. ¡Siente que debería ser la respuesta seleccionada!
UX Andre
4

Usé la solución de filtro personalizada propuesta por @Jess pero en mi proyecto estamos usando Vue junto con TypeScript. Así es como se ve con TypeScript y los decoradores de clases:

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);
  }
}

En este ejemplo, el filtro solo se puede utilizar dentro del componente. Todavía no he intentado implementarlo como un filtro global.

Andreas Bauer
fuente
2

Puedes usar este ejemplo

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

Hay problemas con la precisión de la respuesta aceptada.

la función de redondeo (valor, decimales) en esta prueba funciona. a diferencia del ejemplo simple toFixed.

esta es una prueba del método toFixed vs round.

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 />');

ejemplo de mixin

  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);
      }
    }
  }

Artistan
fuente
1
aún podría usar val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".")después de eso para el. y cambios.
Artistan