Jak formatować waluty w komponencie Vue?

85

Mój komponent Vue wygląda tak:

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

Wynik {{ item.total }}jest

26000000

Ale chcę sformatować to tak:

26.000.000,00

W jquery lub javascript mogę to zrobić

Ale jak to zrobić w komponencie vue?

samuel toh
źródło
1
Jeśli możesz to zrobić w javascript, to możesz to zrobić w Vue ... użyj obliczonych właściwości i zwróć kod javascript.
Happyriri

Odpowiedzi:

83

AKTUALIZACJA: Proponuję użyć rozwiązania z filtrami dostarczonego przez @Jess.

Napisałbym do tego metodę, a potem tam, gdzie musisz sformatować cenę, możesz po prostu umieścić metodę w szablonie i przekazać wartość w dół

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

A potem w szablonie:

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

Przy okazji - nie przywiązywałem zbytniej wagi do zamiany i wyrażeń regularnych. Można to poprawić.enter code here

Belmin Bedak
źródło
12
Zobacz także developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…, aby zapoznać się z wbudowanym zlokalizowanym formatowaniem walut.
Roy J
@RoyJ Dobry chwyt. Właśnie skopiowałem wyrażenie regularne z jednego poprzedniego projektu, w zasadzie mógł zwrócić wartość z metody, jak chciał.
Belmin Bedak
@BelminBedak o czym myślisz return (value/1).toFixed(2).toLocalString();?
retrovertigo
Działa, ale zastępuje wszystkie cyfry dziesiętne przecinkami
Dylan Glockler
Dlaczego nie użyć computedzamiast tego?
localhost
191

Stworzyłem filtr. Filtra można używać na dowolnej stronie.

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

Wtedy mogę użyć tego filtra w ten sposób:

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

Użyłem tych powiązanych odpowiedzi, aby pomóc we wdrożeniu filtra:

Pęto
źródło
5
Mój człowiek! Nawet nie wiedziałem, że możesz to zrobić. Dzięki rozwiązałem mój problem z walutą i wyczyściłem moje miksy, ponieważ większość z nich robiła tego typu rzeczy.
Ominus
2
to jest właściwa odpowiedź
ierdna
Nie Intlma najlepszego wsparcia .
Илья Зеленько
1
A może isNaN(parseFloat(value))raczej niż typeof value !== "number"?
RonnyKnoxville
1
zmieniłbym część warunkową, ponieważ czasami ciąg zwracany przez bazę danych, być może rzutowanie ciągu na numer w tym warunku byłoby lepszą, świetną odpowiedzią.
Andres Felipe
22

W vuejs 2 możesz użyć filtrów vue2, które mają również inne zalety.

npm install vue2-filters


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

Vue.use(Vue2Filters)

Następnie użyj tego w ten sposób:

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

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

Yao Liu
źródło
11

Możesz formatować walutę, pisząc własny kod, ale jest to tylko rozwiązanie w tej chwili - gdy Twoja aplikacja będzie się rozwijać, możesz potrzebować innych walut.

Jest z tym inny problem:

  1. Dla nas - znak dolara jest zawsze przed walutą - 2,00 $,
  2. Dla wybranego PL zwracasz znak po kwocie 2,00 zł.

Myślę, że najlepszą opcją jest użycie kompleksowego rozwiązania do internacjonalizacji, np. Biblioteki vue-i18n ( http://kazupon.github.io/vue-i18n/ ).

Używam tej wtyczki i nie muszę się martwić o takie rzeczy. Proszę spojrzeć na dokumentację - to naprawdę proste:

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

więc po prostu użyj:

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

i ustaw EN-us na 100,00 $ :

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

lub ustaw PL na 100,00 zł :

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

Ta wtyczka zapewnia również różne funkcje, takie jak tłumaczenia i formatowanie daty.

Arkowsky
źródło
8

Komentarz @RoyJ zawiera świetną sugestię. W szablonie możesz po prostu użyć wbudowanych zlokalizowanych ciągów:

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

Nie jest obsługiwany w niektórych starszych przeglądarkach, ale jeśli celujesz w IE 11 i nowsze, powinno być dobrze.

AaronBaker
źródło
Takie proste. Potwierdzono, że działa. Poczuj się, jakby to była wybrana odpowiedź!
UX Andre
5

Użyłem niestandardowego rozwiązania filtrującego zaproponowanego przez @Jess, ale w moim projekcie używamy Vue razem z TypeScript. Tak to wygląda z TypeScript i dekoratorami klas:

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

W tym przykładzie filtr może być używany tylko wewnątrz komponentu. Nie próbowałem jeszcze wdrożyć go jako filtra globalnego.

Andreas Bauer
źródło
2

Możesz użyć tego przykładu

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

Istnieją problemy z precyzją zaakceptowanej odpowiedzi.

funkcja round (value, decimals) w tym teście działa. w przeciwieństwie do prostego przykładu toFixed.

jest to test metody 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 />');

przykład 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
źródło
1
nadal możesz użyć val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".")po tym dla. i zmiany.
Artistan