компонент числового ввода для vue js

avatar
Afshin Gh
7 апреля 2018 в 22:04
4537
1
2

Вот моя реализация с использованием Numeral.js:

        Vue.filter('formatNumber', function (value) {
            return numeral(value).format('0,0.[000]')
        })

        Vue.component('input-number', {
            template: '\
    <div>\
      <label v-if="label">{{ label }}</label>\
      <input\
        ref="input"\
        v-bind:value="displayValue(value)"\
        v-on:input="updateValue($event.target.value)"\
        v-on:focus="selectAll"\
      >\
    </div>\
  ',
            props: {
                value: {
                },
                label: {
                }
            },
            methods: {
                updateValue: function (inputValue) {

                    var valToSend = inputValue

                    var numVal = numeral(valToSend).value()
                    
                    if (isNaN(numVal)) {
                        valToSend = this.value.toString()
                        numVal = numeral(valToSend).value()
                    }

                    var formattedVal = numeral(numVal).format('0,0.[000]')

                    this.$refs.input.value = formattedVal + (valToSend.endsWith('.') ? '.' : '')

                    this.$emit('input', numeral(formattedVal).value())
                    

                },
                displayValue: function (inputValue) {
                    return numeral(inputValue).format('0,0.[000]')
                },
                selectAll: function (event) {
                    // Workaround for Safari bug
                    // http://coderhelper.com/questions/1269722/selecting-text-on-focus-using-jquery-not-working-in-safari-and-chrome
                    setTimeout(function () {
                        event.target.select()
                    }, 0)
                }
            }
        })
        var app = new Vue({
            el: '#app',
            data: {
                pricePerGram: '160000',
                weightInGrams: '1.5',
            },
            computed: {
                totalPrice: function () {
                    return (this.pricePerGram * this.weightInGrams)
                },
                toatlWithVat: function () {
                    return (this.totalPrice *1.09)
                }
            }
        })
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js"></script>

    <div id="app">
        <input-number v-model="pricePerGram" label="Price per gram:"></input-number><br />
        <input-number v-model="weightInGrams" label="Weight in grams:"></input-number><br />
        <div><label>Total price: </label><span dir="ltr">{{totalPrice | formatNumber}}</span></div><br />
        <div><label>Total + Vat: </label><span dir="ltr">{{toatlWithVat | formatNumber}}</span></div><br />
    </div>

Правильно ли я делаю? Есть ли лучший способ реализовать только числовой ввод?

Я хочу это улучшить. Использование Numeral.js не является обязательным. Это просто библиотека, которую я нашел.

несколько вещей, касающихся текущей реализации:

  • Поддерживает разделитель тысяч (по мере ввода).

  • Поддерживает десятичную точку с 3 цифрами (Я хотел бы улучшить это и принять неограниченное количество десятичных цифр. это из-за этого формата 0,0.[000]. Я не смог найти формат, принимающий неограниченное количество десятичных цифр с Numeral.js)

  • допускаются только цифры, запятая и точка (символы не допускаются).

    Я также могу использовать регулярное выражение вместо Numeral.js. Может ли это быть улучшением?

Источник

Ответы (1)

avatar
Filip Sobol
8 апреля 2018 в 09:02
1

Это должно работать (Codepen):

Vue.component("input-number", {
  template: '<input type="string" v-model="model">',

  props: {
    value: {
      type: String,
      required: true,
    }
  },

  computed: {
    model: {
      get() {
        // We extract decimal number, beacause toLocaleString will automagically
        // remove the dot and zeros after it while the user is still typing
        let value = this.value.split(".");
        let decimal = typeof value[1] !== "undefined"
          ? "." + value[1]
          : "";

        return Number(value[0]).toLocaleString("en-GB") + decimal;
      },

      set(newValue) {
        this.$emit("input", newValue.replace(/,/g, ""));
      }
    }
  }
});

new Vue({
  el: "#app",
  data: {
    input: "1234567.890",
  }
});
Afshin Gh
8 апреля 2018 в 21:17
0

Ваш код выглядит действительно чистым и многообещающим. Я могу заменить «toLocaleString» регулярным выражением, но я думаю, что ваш подход чище, чем мой. Спасибо тебе, друг.