Как настроить элемент<input> с более жесткими ограничениями

TLDR; (ОБНОВЛЕНИЕ)

  1. Есть ли способ сообщить, что <input> имеет номер типа, без использования настройки атрибута type=number.
    1. то есть мобильные устройства распознают и отображают цифровую клавиатуру и т.д.
  2. Для <input>, который имеет type=number, есть способ усвоить весь ввод с клавиатуры, который не приводит к действительному числу
    1. До того, как персонаж будет добавлен к вводу браузером, не удаляйте ненужное удаление на keyup

ПОЖАЛУЙСТА, ПРОЧИТАЙТЕ НИЖЕ ДЛЯ ОРИГИНАЛЬНОГО ПОДРОБНОГО ОПИСАНИЯ

Моя проблема заключается в следующем;

У меня есть элемент HTML <input>, который я хочу принимать только числа и быть распознанным на мобильных устройствах в качестве числового поля. Я также хочу, чтобы недопустимые символы проглатывались, как для стандартного type=number глотания запрещенных символов.

Я попробовал очевидное type=number, но у него есть ряд недостатков. В частности, он допускает 'e', '+' и '-' (по крайней мере, в chrome), но их было легко исправить с помощью некоторых JS. Настоящая проблема с "." характер, я хочу иметь возможность вводить числа с плавающей точкой, например '0.10', '5.5054', но я не хочу иметь возможность вводить недопустимые строки, например, '0.10.1'. Я попытался решить эту проблему, допустив только 1 '.' за один раз, но это не удалось, так как input.value обрабатывается браузером, например, '5.' становится '5', '5..' становится нулевым (!), и кажется невозможным получить необработанное строковое значение, введенное во ввод. Вышесказанное означает проверку на наличие ". и принятие мер кажется тупиком...

Основные вопросы:

  1. Есть ли способ пропустить, чтобы проверить и согласовать ввод?
  2. "Есть ли способ отметить вход как число без материально-технического багажа type=number?

Примечание:
* Я понимаю, что вы можете вставить все, что вы хотите, я считаю это поведение патологическим и не должно быть включено в предотвращение ввода.

UPDATE:
Чтобы уточнить, я уже пробовал keypress, keydown и т.д. События, и они не подходят, так как я хочу увидеть, сколько ". существует на входе в настоящее время, чтобы выбрать, разрешить или нет другое. В этот момент браузер массирует input.value для удаления '. Я хочу условно разрешить символы на основе текущего числа '. которые были введены.

Пример:
HTML (угловая привязка стиля для краткости)

<input type="number" (keydown)="keyDown()">

JS

function keyDown($event: KeyboardEvent) {
  const inputField = // obtain reference to input element
  const value = inputField.value;
  if ( value.indexOf('.') !== -1 && $event.key === '.') { // disallow another . if one is present
    // ! input field prunes . so this check isn't sufficient
    $event.preventDefault();
    return;
  }

  // This is the crux of the problem e.g.
  // type 5. into input field, value === 5
  // type 5.. into the input field, value === null
  // Since the . char is removed by the input element there no way to know how many are present!
  console.log(value);
}

Ответ 1

  Есть ли способ сообщить, что <input> имеет номер типа, без использования настройки атрибута type=number. то есть мобильные устройства распознают и отображают цифровую клавиатуру и т.д.

Используйте inputmode="decimal" вместо type="number", чтобы подать сигнал мобильному устройству на ввод с клавиатуры. Таким образом, вы можете продолжать использовать type="text" и обрабатывать ввод по мере необходимости.

Для получения дополнительной информации см. MDN и inputtypes.com для тестирования устройства.

Ответ 2

Немного другой подход. Это позволяет цифры, только 1 период, и возврат. Все остальные KeyboardEvent.key, включая ctrl + v и ctrl + c, игнорируются. Но если вы хотите позволить им, вы можете сделать это.

Чтобы проверить, является ли символ одной из цифр 10, я использую event.key, поскольку они могут иметь два разных кода: Digits[0-9] и Numpad[0-9]. Но для периода и возврата я использую event.code, поскольку у них есть только один код.

const input = document.querySelector("#number_input");

const App = {
  isDigit: function(key) {
    const digits = [
      "0",
      "1",
      "2",
      "3",
      "4",
      "5",
      "6",
      "7",
      "8",
      "9"
    ];
    return digits.includes(key);
  },
  isPeriod: function(code) {
    return code === "Period";
  },
  isBackSpace: function(code) {
    return code === "Backspace";
  },
  handleEvent: function(event) {
    const key = event.key;
    const code = event.code;
    const value = input.value;
    if (App.isDigit(key) || App.isPeriod(code) || App.isBackSpace(code)) {
      if (App.isPeriod(code) && value.indexOf(key) !== -1) {
        event.preventDefault();
      }
    } else {
      event.preventDefault();
    }
  }
};

input.onkeydown = App.handleEvent
<input id="number_input" />

Ответ 3

вызвать специальную функцию для onkeypress и проверить, введен или нет ваш разрешенный символ. Если нет - запретите поведение по умолчанию.

let special = document.getElementById('special_input');
special.addEventListener("keypress", function(e) {
  let dot = 46;
  // allowed char: 0-9, .
  let allow_char = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, dot];
  if (allow_char.indexOf(e.which) !== -1) {
    // only 1 dot
    if (e.which == 46 && special.value.indexOf('.') !== -1)
      e.preventDefault();
  } else {
    e.preventDefault();
  }
});
<input id='special_input'>

Ответ 4

обновлено

Ответ обновляется в соответствии с изменениями требований.

хорошо, я пытаюсь решить еще одну проблему, и это вставить

согласно следующему коду, вы ничего не можете вставить, вы можете только вставить цифры, если вы попытаетесь вставить строку, поле ввода автоматически опустеет :)

  let special = document.getElementById('inputField');
  special.addEventListener("keypress", function(e) {
  let dot = 46;
  // allowed char: 0-9, .
  let allow_char = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, dot];
  if (allow_char.indexOf(e.which) !== -1) {
    // only 1 dot
    if (e.which == 46 && special.value.indexOf('.') !== -1)
      e.preventDefault();
  } else {
    e.preventDefault();
  }
});

function checkString()
{
  setTimeout(() => {
  var value = document.getElementById("inputField").value;
  value = parseInt(value);
    if(isNaN(value))
      document.getElementById("inputField").value = "";
    }, 100);

}
  <input type="number" id="inputField" onpaste="checkString()"/>

Ответ 5

Проверьте правду с помощью

value == parseFloat(value)

parseFloat() захватит первую десятичную точку и удалит все дополнительные.

Использование "==" вместо "===" гарантирует, что эталонное значение не изменилось.

function keyDown($event: KeyboardEvent) {
    const inputField = // obtain reference to input element
    const value = inputField.value;
    if ( value == parseFloat(value)) { // disallow another . if one is present
      // ! input field prunes . so this check isn't sufficient
      $event.preventDefault();
      return;
    }

    // This is the crux of the problem e.g.
    // type 5. into input field, value === 5
    // type 5.. into the input field, value === null
    // Since the . char is removed by the input element there no way to know how many are present!
    console.log(value);
  }

Вот аналогичный тест, который вы можете запустить в node.js, чтобы убедиться, что он выполняет то, для чего вы собираетесь.

function numCheck (value) {
    if (value == parseFloat(value)) { 
        console.log(value)
    } else {
        console.log('not a number')
    }
}

numCheck("5");
numCheck("5.5");
numCheck("5.5.5");
numCheck("A");

Ответ 6

Для ограничений, Regex - лучший способ. Зарегистрировать прослушиватель событий при нажатии клавиш

numbersOnly(event) {
    const numbers = /^([0-9])$/;
    const result = numbers.test(event.key);
    return result;
}

Выше функция проглотит кодировку, если она не соответствует регулярному выражению

Javascript Regex: проверка двойного/плавающего

Над ссылкой есть регулярное выражение, которое позволяет удваивать/плавать. Надеюсь, это поможет :)

Ответ 7

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

HTML:

<input type="number" id="num" step="0.1"/>

JS:

var numField = document.getElementById('num');
numField.addEventListener("keyup", event => {
   if(!numField.validity.valid)
   {
      alert('invalid input');
   }
});

Некоторые тесты:

34    -> valid
3.4   -> valid
e     -> invalid
+4    -> valid    
3.4.  -> invalid
3.4.. -> invalid
.4    -> valid (evaluates to 0.4)
3e+2  -> valid
1e    -> invalid
eee   -> invalid
-0.3e+1 -> valid
..32e.. -> invalid

Это работает как со вставкой, так и с вводом значений.

UPDATE:

Оригинальный вопрос немного многословен. Я пытаюсь разбить его и ответить по частям.

Input [type = "number"] разрешает доступ к значению, только если оно допустимо и в противном случае возвращает пустое значение. Таким образом, вы можете знать, является ли значение правильным или нет, однако вы не можете получить недопустимое значение.

Вы можете обойти это, помещая отдельные нажатия клавиш в буфер. Однако поддержание синхронизации между буфером и фактическим значением является сложной задачей из-за копирования/вставки, поля ввода, поглощающего определенные клавиши, перемещения курсора и вставки клавиш и т.д. Реализация надежной кроссплатформенной поддержки для всего этого кажется излишним. Лучшим подходом было бы реализовать другие средства для ввода числа, например, слайдер Этот ресурс охватывает основы проектирования числовых входов

Таким образом, вам остается знать, действителен ли текущий ввод и была ли нажата последняя клавиша. Проблема в том, что некоторые неверные входные данные, например, "4." может привести к действительному вводу "4.1". Таким образом, просто глотать последнюю клавишу в случае, если ввод становится недействительным, не может быть и речи.

Вы могли бы реализовать правило, согласно которому, если недопустимый ввод не превращается в действительный в течение 2 нажатий клавиш (или 1 секунды), ввод возвращается к последнему действительному состоянию, поглощающему недопустимый ввод. Тем не менее, я бы сказал, что это создает проблемы с UX, потому что пользователи могут не привыкать к такому поведению, и это открывает двери для пользователей, предоставляющих технически допустимые, но нежелательные значения.

Core questions:

  1. Есть ли способ пропустить, чтобы проверить и согласовать ввод?

  2. Можно ли пометить вход как число без материально-технического багажа типа = число?

  1. Очевидно нет.

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

Ответ 8

Это может быть то, что вы ищете:
Этот вход съедает все символы, кроме чисел и "."

let prev = "";
function keyUp(event) {
    if ((!event.target.value && event.keyCode !== 8) || event.target.value.indexOf('e') !== -1 || parseFloat(event.target.value) == NaN) {
        event.target.value = prev;
    } else {
        prev = event.target.value;
    }
}
<input type="number" onkeyup="keyUp(event)">