Как ограничить несколько полей ввода (которые используют v-модель), чтобы они принимали только числа в Vue.js (без повторения кода для каждого поля ввода)?

У меня есть несколько полей ввода, и я хочу, чтобы они принимали только числа в Vue.js.
Я хочу запретить пользователю вводить любые символы, кроме цифр от 0 до 9. Я уже сделал это успешно, выполнив это (это решение копировать-вставить доказательство):

Код в шаблоне Vue.js:

<input type="text" name="priceMax" class="input" @input="correctNumberInput" />

Метод, удаляющий все, кроме чисел:

correctNumberInput: function(event){   
          event.target.value = event.target.value.replace(/[^0-9]/g, "");
        }

Это отлично работало на нескольких полях.

Здесь возникает проблема: по другой причине мне нужно было использовать v-model в этих полях ввода. После добавления v-модели мой метод больше не работает. Я предполагаю, что это потому, что v-model также использует событие ввода под капотом. Таким образом, только добавление v-модели останавливает ее работу:

<input type="text" name="priceMax" class="input" @input="correctNumberInput" v-model="priceMax" />

У меня есть несколько возможных решений, но все они включают много повторяющегося кода.

Например, я мог бы добавить наблюдателей для каждого поля ввода, но это было бы много повторяющегося кода (потому что мне нужно было бы сделать это для каждого поля ввода). У меня есть 5 полей ввода, поэтому в основном мне нужно написать 5 почти идентичных наблюдателей. Я бы хотел избежать этого, если это возможно ... Например:

watch:{
   number(){
      this.priceMax = this.priceMax.replace(/[^0-9]/g, "");
   }
}

Есть ли способ решить эту проблему и сделать ее настолько простой, насколько было мое решение, без повторения кода? Было бы неплохо иметь решение, защищенное от копирования. Все предложения приветствуются! Заранее спасибо!


person Vasilije Bursac    schedule 25.08.2020    source источник
comment
Может быть, этот поможет   -  person mare96    schedule 26.08.2020
comment
Спасибо за ответ! Эти решения хороши, но самая большая проблема для меня - это повторение кода. У меня есть 5 полей ввода, поэтому в основном мне нужно написать 5 почти идентичных наблюдателей. Я бы хотел этого избежать, если это возможно ...   -  person Vasilije Bursac    schedule 26.08.2020


Ответы (2)


Я пробовал протестировать какой-то код. Вот что у меня есть (ссылка на пример ):

<template>
  <div>
    <div>
      <input
        type="text"
        name="priceMin"
        class="input"
        v-model="priceMin"
        @input="correctNumberInput"
      >
      <label v-html="priceMin"></label>
    </div>
    <div>
      <input
        type="text"
        name="priceMax"
        class="input"
        v-model="priceMax"
        @input="correctNumberInput"
      >
      <label v-html="priceMax"></label>
    </div>
  </div>
</template>

<script>
export default {
  name: "MyInput",
  data: () => {
    return {
      priceMin: "",
      priceMax: ""
    };
  },
  methods: {
    correctNumberInput: function(event, data) {
      const name = event.target.name;
      let value = String(this[name]).replace(/[^0-9]/g, "");
      if (value) {
        this[name] = parseInt(value, 10);
      } else {
        this[name] = "";
      }
    }
  }
};
</script>

<style scoped>
input {
  border: 1px solid black;
}
</style>

Это код:

correctNumberInput: function(event, data) {
  const name = event.target.name;
  let value = String(this[name]).replace(/[^0-9]/g, "");
  if (value) {
    this[name] = parseInt(value, 10);
  } else {
    this[name] = "";
  }
}

Итак, я использовал вашу функцию, но я не меняю event.target.value, я меняю data. Поэтому мне нужно знать название этих данных, поэтому я использую атрибут name из полей ввода (const name = event.target.name;)

Обновить

Если у нас есть input type=number, то у него странное (пустое) значение внутри обратного вызова @input. Кажется, лучше использовать фильтр клавиатуры (пример здесь):

Основная идея иметь фильтр клавиатуры:

filterDigitKeys: function(event) {
  const code = window.Event ? event.which : event.keyCode;
  const isSpecial =
    code === 37 ||
    code === 39 ||
    code === 8 ||
    code === 46 ||
    code === 35 ||
    code === 36;
  const isDigit = code >= 48 && code <= 57;
  const isKeypad = code >= 96 && code <= 105;
  if (!isSpecial && !isDigit && !isKeypad) {
    // if not number or special (arrows, delete, home, end)
    event.preventDefault();
    return false;
  }
}

И прикрепите его к входам:

<input type="number" min="0" name="numberInput" class="input"
    v-model.number="numberInput" @keydown="filterDigitKeys">

Примечание: если мы оставим только обработчик @keydown, то мы не будем фильтровать вставку текста в наши входы (но ctrl + v все равно не работает, только мышью).

person Anton    schedule 26.08.2020
comment
Огромное спасибо! Это решение, которое я искал! Очень умно и элегантно. Я просто не знал, как это сделать, потому что я новичок в Vue.js и не знал об использовании [] с этим. Я определенно узнал что-то новое из вашего ответа! Спасибо еще раз! - person Vasilije Bursac; 26.08.2020
comment
@VasilijeBursac это не из Vue, это из самого JS. Любой объект на самом деле является картой, поэтому a.b и a['b'] работают одинаково. - person Anton; 26.08.2020
comment
О, я не знала, что это одно и то же. Спасибо за прекрасное объяснение! - person Vasilije Bursac; 26.08.2020
comment
Извините, если я вас беспокою, но знаете ли вы, почему этот код не работает для полей ввода чисел? Если вы попытаетесь ввести e, - и т. Д. В поле ввода числа, он по-прежнему показывает, что в поле, он не заменяет это на (пустая строка). Я не понимаю, почему это не работает, потому что я раньше использовал ту же функцию для числовых полей, и она отлично работала. Код проверки с добавленным числовым полем: пример с добавленным поле ввода числа - person Vasilije Bursac; 26.08.2020
comment
@VasilijeBursac Я добавил обновление к своему ответу. Проверь это - person Anton; 26.08.2020
comment
Спасибо за ответ, это определенно хороший аргумент! По сути, у него было пустое значение внутри обратного вызова @input и внутри свойства в данных, но поле не было пустым. Что решило проблему для меня, так это добавление event.target.value = event.target.value.replace(/[^0-9]/g, ""); перед let value = String(this[name]).replace(/[^0-9]/g, "");. Это просто удостоверилось, что мы также отфильтровали и очистили поле. Я понимаю, что это не лучшее решение, поэтому попробую и ваше! Спасибо за все Антон. С наилучшими пожеланиями! - person Vasilije Bursac; 26.08.2020

Может быть, вы можете попробовать это:

<input type="number" name="priceMax" class="input" @input="correctNumberInput" v-model.number="priceMax" />

С этого сайта: щелкните.

person Anton    schedule 25.08.2020
comment
Спасибо за ответ! К сожалению, это не помогает, потому что я хочу запретить пользователю вводить какие-либо символы, кроме цифр от 0 до 9, и ваше решение будет приводить только тип ввода пользователя из String в Number. - person Vasilije Bursac; 26.08.2020