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


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


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:


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


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.


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.


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.


2

Puedes usar este ejemplo

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

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


1
aún podría usar val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".")después de eso para el. y cambios.
Artistan
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.