Отключить прокрутку на `<input type = number>`

121

Можно ли отключить колесо прокрутки, изменяя число в поле ввода номера? Я испортил специфичный для webkit CSS, чтобы удалить счетчик, но я хотел бы полностью избавиться от этого поведения. Мне нравится использоватьtype=number потому что он вызывает красивую клавиатуру на iOS.

kjs3
источник
7
используйте тип ввода tel (type = "tel") вместо type = number. Появится всплывающая клавиатура с цифрами iOS.
Praveen Vijayan
Что произойдет, если вы добавите onscrollобработчик только event.preventDefault()в нем?
robertc
14
По моему скромному мнению, я даже не думаю, что это должна быть особенность. Если бы я имел право голоса в разработке браузера, я бы, вероятно, настоял на удалении этой функции. Это только раздражает, и я не знаю никого, кто бы им действительно воспользовался.
Kirkland
3
Я полностью согласен с тобой, Киркланд. Прокрутка страницы с формой - это просто плохой UX, и когда элемент ввода числа попадает под вашу мышь, он начинает увеличиваться, и страница перестает прокручиваться. Совершенно дезориентирующий.
kjs3
3
@PraveenVijayan: Хотя это обходной путь, он противоречит любой причине для использования новых типов ввода html5. В будущем может случиться так, что телефоны предоставят вам возможность выбирать номер из контактов или чего-либо еще, что будет выглядеть очень странно, если вы имели в виду, что это номер другого типа.
awe

Ответы:

92

Предотвратить поведение по умолчанию события колеса мыши для элементов input-number, как это было предложено другими (вызов «blur ()» обычно не является предпочтительным способом сделать это, потому что это не то, что хочет пользователь).

НО. Я бы избегал постоянно прослушивать событие колесика мыши на всех элементах input-number и делал это только тогда, когда элемент находится в фокусе (когда проблема существует). В противном случае пользователь не сможет прокручивать страницу когда указатель мыши находится где-нибудь над элементом input-number.

Решение для jQuery:

// disable mousewheel on a input number field when in focus
// (to prevent Cromium browsers change the value when scrolling)
$('form').on('focus', 'input[type=number]', function (e) {
  $(this).on('wheel.disableScroll', function (e) {
    e.preventDefault()
  })
})
$('form').on('blur', 'input[type=number]', function (e) {
  $(this).off('wheel.disableScroll')
})

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

Grantzau
источник
2
Отличный ответ. Думаю, если бы я делал это сегодня, я бы использовал Modernizr.touch для условного применения прослушивателя событий на устройствах без сенсорного экрана. В основном то, что сказал ниже user2863715.
kjs3
Отличный ответ, но, по крайней мере, в webkit, это также предотвращает прокрутку окна, когда курсор находится над элементом ввода. Я думал, что события колесика мыши тоже должны пузыриться.
Райан МакГири
При применении функции отключения прокрутки только к элементу, когда он находится в фокусе, это не должно препятствовать прокрутке, когда мышь находится над элементом ввода. Но это не позволяет прокручивать окно, когда элемент в фокусе. И да, почему событие
колесика мыши не пузырится
6
Это хорошее исправление поведения, которого вообще не должно быть.
Джонни
Это не работает на большинстве платформ типа unix gnome, osx, android (с помощью мыши), поскольку поведение прокрутки не требует, чтобы ввод был сфокусирован. В качестве альтернативы, я просто использовал текстовый тип ввода и наложил на него свое ограничение по количеству (потеря клавиш вверх / вниз, но также может быть добавлено с помощью js)
zeachco
40
$(document).on("wheel", "input[type=number]", function (e) {
    $(this).blur();
});
stovroz
источник
2
это тот, который идеален.
Патрик Ласло
Это хорошо работает. Спасибо.
Vijay S
21

Один слушатель событий, чтобы управлять ими всеми

Это похоже на @Simon Перепелица «s ответа в чистом JS, но немного проще, так как она кладет слушатель событий на элементе документа и проверяет , если сфокусированный элемент ввод номера:

document.addEventListener("wheel", function(event){
    if(document.activeElement.type === "number"){
        document.activeElement.blur();
    }
});

Если вы хотите отключить прокрутку значений в некоторых полях, но не в других, просто сделайте это вместо этого:

document.addEventListener("wheel", function(event){
    if(document.activeElement.type === "number" &&
       document.activeElement.classList.contains("noscroll"))
    {
        document.activeElement.blur();
    }
});

с этим:

<input type="number" class="noscroll"/>

Если вход имеет класс noscroll, он не изменится при прокрутке, в противном случае все останется прежним.

Протестируйте здесь с помощью JSFiddle

Питер Ракманьи
источник
Я вижу, это было отклонено. Если вы заметили проблему, пожалуйста, оставьте комментарий, проголосовав против. Если я что-то пропустил, то хотел бы узнать, что это такое. Спасибо.
Питер Ракманьи
1
Для современного браузера используйте событие wheelвместо mousewheel. Ссылка: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event PS. Я не тот, кто голосует против.
vee
19
input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(event){ this.blur() })

http://jsfiddle.net/bQbDm/2/

Для примера jQuery и кросс-браузерного решения см. Связанный вопрос:

Слушатель событий HTML5 для прокрутки ввода чисел - только Chrome

Симон Перепелица
источник
2
Спасибо, Сеймон, мне удалось сделать это для ввода всех чисел с помощью jQuery следующим образом: $(':input[type=number]' ).live('mousewheel',function(e){ $(this).blur(); });я использовал размытие вместо предотвращения по умолчанию, чтобы он не блокировал прокрутку страницы!
Тибо Колсон,
Хорошее дополнение к размытию, я не знал, что вы все еще можете разрешить прокрутку страницы. Я обновил свой ответ.
Симон Перепелица
13
FYI, live()устарел. Теперь вы должны использовать on(): $(':input[type=number]').on('mousewheel',function(e){ $(this).blur(); });
Саид Зебардаст
3
@SaeidZebardast Ваш комментарий заслуживает ответа
snumpy
Для современного браузера используйте событие wheelвместо mousewheel. Ссылка: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
vee
16

Вы можете просто использовать атрибут HTML onwheel .

Этот параметр не влияет на прокрутку других элементов страницы.

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

Кроме того, вы можете удалить стрелки ввода с помощью CSS.

input[type="number"]::-webkit-outer-spin-button, 
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
input[type="number"] {
    -moz-appearance: textfield;
}
<input type="number" onwheel="this.blur()" />

Майкон Матеус
источник
1
Спасибо брат!! он отлично работал в Angular - Материал 6
Насируддин Сайед
источник: css-tricks.com/snippets/css/turn-off-number-input-spinners
Хафиз Темури
Мы можем найти этот CSS во многих источниках. В любом случае CSS - это только бонус. Настоящее решение вопроса - это атрибут HTML onwheel. ;-)
Maikon Matheus
5
Мне нравится это решение! Спасибо. В моем случае все onBlur()оказалось не так, как ожидалось. return falseВместо этого я установил простое, чтобы действительно «ничего не делать на колесе». <input type="number" onwheel="return false;">
Дэниел
14

@Semyon Perepelitsa

Для этого есть лучшее решение. Размытие удаляет фокус с ввода, и это побочный эффект, который вам не нужен. Вместо этого вы должны использовать evt.preventDefault. Это предотвращает поведение ввода по умолчанию при прокрутке пользователем. Вот код:

input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(evt){ evt.preventDefault(); })
Dibran
источник
6
Это работает, но событие не всплывает, поэтому страница не прокручивается. Есть ли способ сохранить поведение по умолчанию (прокрутка страницы) без размытия?
GuiGS
Для современного браузера используйте событие wheelвместо mousewheel. Ссылка: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
vee
7

Сначала вы должны остановить событие колесика мыши:

  1. Отключение с помощью mousewheel.disableScroll
  2. Перехватывая это с e.preventDefault();
  3. Убрав фокус с элемента el.blur();

Первые два подхода останавливают прокрутку окна, а последний удаляет фокус с элемента; Оба эти результата являются нежелательными.

Один из обходных путей - использовать el.blur()и перефокусировать элемент после задержки:

$('input[type=number]').on('mousewheel', function(){
  var el = $(this);
  el.blur();
  setTimeout(function(){
    el.focus();
  }, 10);
});
Джеймс ЭДжей
источник
3
Красивое решение, но при тестировании я обнаружил, что у этого решения есть побочный эффект в виде кражи фокуса. Я настроил это, чтобы иметь: тест, чтобы увидеть, был ли элемент в фокусе: var hadFocus = el.is(':focus');перед размытием, а затем охранник, чтобы установить тайм-аут только в том случае, если hasFocs был истинным.
Роб Доусон
3

Для всех, кто работает с React и ищет решение. Я обнаружил, что самый простой способ - использовать свойство onWheelCapture в компоненте Input следующим образом:

onWheelCapture={e => { e.target.blur() }}

Алеш Хромец
источник
2

Предоставленные ответы не работают в Firefox (Quantum). Слушатель событий необходимо изменить с колеса мыши на колесо:

$(':input[type=number]').on('wheel',function(e){ $(this).blur(); });

Этот код работает в Firefox Quantum и Chrome.

Матиас Банк
источник
2

Машинописный вариант

TypeScript должен знать, что вы работаете с HTMLElement для обеспечения безопасности типов, иначе вы увидите много Property 'type' does not exist on type 'Element'типов ошибок.

document.addEventListener("mousewheel", function(event){
  let numberInput = (<HTMLInputElement>document.activeElement);
  if (numberInput.type === "number") {
    numberInput.blur();
  }
});
винил
источник
1

Пытаясь решить эту проблему для себя, я заметил, что на самом деле можно сохранить прокрутку страницы и фокус ввода при отключении изменения числа, попытавшись повторно запустить событие catch на родительском элементе того, <input type="number"/>на котором оно было поймано. , просто так:

e.target.parentElement.dispatchEvent(e);

Однако это вызывает ошибку в консоли браузера и, вероятно, не гарантирует, что будет работать везде (я тестировал только в Firefox), поскольку это намеренно недействительный код.

Другое решение, которое хорошо работает, по крайней мере, в Firefox и Chromium, - это временно создать <input>элемент readOnly, например:

function handleScroll(e) {
  if (e.target.tagName.toLowerCase() === 'input'
    && (e.target.type === 'number')
    && (e.target === document.activeElement)
    && !e.target.readOnly
  ) {
      e.target.readOnly = true;
      setTimeout(function(el){ el.readOnly = false; }, 0, e.target);
  }
}
document.addEventListener('wheel', function(e){ handleScroll(e); });

Один из побочных эффектов, который я заметил, заключается в том, что поле может мигать на долю секунды, если у вас другой стиль для readOnlyполей, но, по крайней мере, для моего случая это не кажется проблемой.

Точно так же (как объяснено в ответе Джеймса) вместо изменения readOnlyсвойства вы можете blur()заполнить поле, а затем focus()вернуть его обратно, но опять же, в зависимости от используемых стилей, может возникнуть некоторое мерцание.

В качестве альтернативы, как упоминалось в других комментариях здесь, вы можете просто позвонить preventDefault()на мероприятие. Предполагая, что вы обрабатываете wheelсобытия только для числовых входов, которые находятся в фокусе и под курсором мыши (это то, что означают три вышеуказанных условия), негативное влияние на взаимодействие с пользователем будет практически нулевым.

Римас Куделис
источник
1

Если вам нужно решение, для которого не нужен JavaScript, можно использовать сочетание некоторых функций HTML с псевдоэлементом CSS:

span {
  position: relative;
  display: inline-block; /* Fit around contents */
}

span::after {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0; /* Stretch over containing block */
  cursor: text; /* restore I-beam cursor */
}

/* Restore context menu while editing */
input:focus {
  position: relative;
  z-index: 1;
}
<label>How many javascripts can u fit in u mouth?
  <span><input type="number" min="0" max="99" value="1"></span>
</label>

Это работает, потому что нажатие на содержимое <label> , связанное с полем формы, приведет к фокусированию поля. Однако «оконное стекло» псевдоэлемента над полем будет блокировать доступ событий колесика мыши к нему.

Недостатком является то, что кнопки счетчика вверх / вниз больше не работают, но вы сказали, что все равно их удалили.


Теоретически можно восстановить контекстное меню, не требуя, чтобы ввод был сначала сфокусирован: :hoverстили не должны срабатывать, когда пользователь прокручивает, поскольку браузеры избегают их пересчета во время прокрутки из соображений производительности, но я не полностью кроссбраузерность / устройство протестировал это.

Tigt
источник
0
function fixNumericScrolling() {
$$( "input[type=number]" ).addEvent( "mousewheel", function(e) {
    stopAll(e);     
} );
}

function stopAll(e) {
if( typeof( e.preventDefault               ) != "undefined" ) e.preventDefault();
if( typeof( e.stopImmediatePropagation     ) != "undefined" ) e.stopImmediatePropagation();
if( typeof( event ) != "undefined" ) {
    if( typeof( event.preventDefault           ) != "undefined" ) event.preventDefault();
    if( typeof( event.stopImmediatePropagation ) != "undefined" ) event.stopImmediatePropagation();
}

return false;
}
НСБ
источник
0

Самое простое решение - добавить onWheel={ event => event.currentTarget.blur() }}сам ввод.

TSlegaitis
источник