Лучший способ интеграции BigNumber.js во Vue проект

Как можно реализовать интеграцию BigNumber.js в проект для использования в формах?

Вариант 1: Можно использовать computed геттеры и сеттеры, где в сеттерах оборачивать value в BigNumber:

// template
<input v-model="fieldValue" />

// computed
computed: {
    fieldValue: {
       get()  { return this.form.count.toString() },
       set(v) { this.form.count = new BigNumber(v) }
    }
}

Минус первого варианта в том, что под каждое поле нужно делать computed свойство с геттерами и сеттерами.

Вариант 2 Компонент обертка, который бы инкапсулировал конвертацию обычного числового типа в bigNubmer и наоборот. Минус: Необходимость пробрасывать пропсы и слоты через обертку в кастомный компонент. (Конкретно в моем случае я использую сторонний компонент)

Вариант 3 Использовать @change событие и :value атрибут у компонента input вместо v-model. Т.е. в обработчике change оборачивать введенное число в BigNumber и в value получать его значение. минус: не используем v-model, что, как по мне, куда лаконичнее

Вариант 4 Кастомная директива по типу v-model? v-big-number, например

Какие еще решения можете предложить? Заранее спасибо!

ссылка на либу https://github.com/MikeMcl/bignumber.js


Ответы (1 шт):

Автор решения: Vasiliy Rusin

2 и 4 вариант звучат хорошо, но я бы все же пердпочел второй вариант.

Хотя деректива и заманчива, но вам по факту придется реализовывать чуть ли не свой собственный v-model, что со всеми пограничными случаями не такая тревиальная задача как может показаться.

Что касается минусов второго варианта, пропсы пробросить не сложно, слотов у Вас вряд ли наберется даже десяток, из плюсов — Вы инкапсулируете логику в одном месте.

Ниже практически полный пример, Вам нужно лишь настроить его под свои нужды.

Edit https://ru.stackoverflow.com/questions/1285348

<template>
  <SomeUILibraryInput
    v-bind="$attrs"
    v-on="listeners"
    v-model="model"
    :class="className"
    :style="componentStyles"
  >
    <slot />
  </SomeUILibraryInput>
</template>

<script>
  import SomeUILibraryInput from "./SomeUILibraryInput.vue";
  import {
    BigNumber
  } from "bignumber.js";

  export default {
    name: "BigNumberInput",
    components: {
      SomeUILibraryInput,
    },

    props: {
      value: {
        type: null,
        default: null,
      },

      className: {
        type: [String, Array, Object],
        default: null,
      },

      componentStyles: {
        type: [String, Array, Object],
        default: null,
      },
    },

    computed: {
      model: {
        get() {
          return this.value.toString();
        },

        set(value) {
          this.$emit("input", new BigNumber(value || 0));
        },
      },

      listeners() {
        const {
          input,
          ...other
        } = this.$listeners;

        return other;
      },
    },
  };
</script>

<style></style>

→ Ссылка