ปิดการใช้งานการเลื่อนบน `<input type = number>"


121

เป็นไปได้หรือไม่ที่จะปิดใช้งานล้อเลื่อนที่เปลี่ยนหมายเลขในช่องหมายเลขอินพุต ฉันยุ่งกับ CSS เฉพาะ webkit เพื่อลบสปินเนอร์ แต่ฉันต้องการกำจัดพฤติกรรมนี้โดยสิ้นเชิง ฉันชอบใช้type=numberเพราะมันแสดงคีย์บอร์ดที่ดีบน iOS


7
ใช้ประเภทอินพุต tel (type = "tel") แทนการใช้ type = number มันจะป๊อปอัพแป้นพิมพ์ตัวเลขของ iOS
Praveen Vijayan

จะเกิดอะไรขึ้นเมื่อคุณเพิ่มonscrollตัวจัดการที่มีเพียงแค่event.preventDefault()ในนั้น
robertc

14
ในความเห็นที่ต่ำต้อยของฉันฉันไม่คิดว่านี่ควรเป็นคุณลักษณะด้วยซ้ำ ถ้าฉันพูดในการพัฒนาเบราว์เซอร์ฉันอาจจะผลักดันให้ลบคุณสมบัตินี้ ไม่มีอะไรนอกจากน่ารำคาญและฉันไม่รู้ว่าใครจะใช้มันจริงๆ
Kirkland

3
ฉันเห็นด้วยกับคุณเคิร์กแลนด์ UX ไม่ดีที่จะต้องเลื่อนหน้าด้วยแบบฟอร์มและเมื่อองค์ประกอบการป้อนตัวเลขอยู่ใต้เมาส์ของคุณมันจะเริ่มเพิ่มขึ้นและหน้าจะหยุดเลื่อน สับสนโดยสิ้นเชิง
kjs3

3
@PraveenVijayan: แม้ว่านี่จะเป็นวิธีแก้ปัญหา แต่ก็ขัดต่อเหตุผลใด ๆ ในการใช้ประเภทอินพุต html5 ใหม่ ในอนาคตอาจเป็นไปได้ว่าโทรศัพท์จะให้คุณเลือกหมายเลขจากรายชื่อติดต่อหรืออะไรก็ได้ซึ่งจะดูแปลกมากหากคุณหมายถึงหมายเลขประเภทอื่น
กลัว

คำตอบ:


92

ป้องกันพฤติกรรมเริ่มต้นของเหตุการณ์ mousewheel บนองค์ประกอบหมายเลขอินพุตตามที่แนะนำโดยผู้อื่น (โดยปกติการเรียก "เบลอ ()" จะไม่ใช่วิธีที่ต้องการในการดำเนินการเนื่องจากจะไม่เป็นไปตามที่ผู้ใช้ต้องการ)

แต่. ฉันจะหลีกเลี่ยงการฟังเหตุการณ์ mousewheel ในองค์ประกอบหมายเลขอินพุตทั้งหมดตลอดเวลาและจะทำก็ต่อเมื่อองค์ประกอบนั้นอยู่ในโฟกัส (นั่นคือเมื่อเกิดปัญหา) มิฉะนั้นผู้ใช้จะไม่สามารถเลื่อนหน้าเมื่อตัวชี้เมาส์อยู่ที่ใดก็ได้เหนือองค์ประกอบหมายเลขอินพุต

โซลูชันสำหรับ 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')
})

(มอบหมายกิจกรรมโฟกัสให้กับองค์ประกอบแบบฟอร์มรอบข้าง - เพื่อหลีกเลี่ยงผู้ฟังเหตุการณ์จำนวนมากซึ่งไม่ดีต่อประสิทธิภาพ)


2
คำตอบที่ดี ฉันคิดว่าถ้าฉันทำสิ่งนี้ในวันนี้ฉันจะใช้ Modernizr.touch เพื่อใช้ตัวฟังเหตุการณ์บนอุปกรณ์ที่ไม่ใช่ระบบสัมผัส โดยทั่วไปสิ่งที่ผู้ใช้ 2863715 กล่าวไว้ด้านล่าง
kjs3

คำตอบที่ดี แต่อย่างน้อยใน webkit สิ่งนี้ยังป้องกันไม่ให้เลื่อนหน้าต่างขณะที่เคอร์เซอร์อยู่เหนือองค์ประกอบอินพุต ฉันคิดว่าเหตุการณ์ mousewheel ควรจะฟองด้วย
Ryan McGeary

เมื่อใช้ฟังก์ชันปิดการใช้งานเลื่อนกับองค์ประกอบเมื่ออยู่ในโฟกัสเท่านั้นสิ่งนี้ไม่ควรป้องกันการเลื่อนเมื่อเมาส์อยู่เหนือองค์ประกอบอินพุต แต่จะป้องกันไม่ให้เลื่อนหน้าต่างเมื่อองค์ประกอบอยู่ในโฟกัส และใช่เหตุใดเหตุการณ์
mousewheel จึง

6
นี่เป็นการแก้ไขพฤติกรรมที่ดีที่ไม่ควรเกิดขึ้นตั้งแต่แรก
จอนนี่

สิ่งนี้ใช้ไม่ได้กับ gnome แพลตฟอร์มประเภท unix ส่วนใหญ่, osx, android (ด้วยเมาส์) เนื่องจากพฤติกรรมการเลื่อนไม่จำเป็นต้องให้อินพุตถูกโฟกัส หรืออีกวิธีหนึ่งฉันใช้อินพุตประเภทข้อความและ จำกัด จำนวนของฉันไว้ (การสูญเสียคีย์ลัดขึ้น / ลง แต่สามารถเพิ่มด้วย js ได้เช่นกัน)
zeachco


21

ผู้ฟังเหตุการณ์หนึ่งที่จะปกครองพวกเขาทั้งหมด

สิ่งนี้คล้ายกับคำตอบของ@Simon Perepelitsaใน pure 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


ฉันเห็นว่าสิ่งนี้ถูกลดลง หากคุณพบปัญหาโปรดแสดงความคิดเห็นพร้อมกับการโหวตลด หากฉันพลาดบางสิ่งบางอย่างฉันต้องการเรียนรู้ว่ามันคืออะไร ขอบคุณ
Peter Rakmanyi

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
ขอบคุณ Seymon ฉันจัดการกับการป้อนตัวเลขทั้งหมดด้วย jQuery ด้วยวิธีนี้: $(':input[type=number]' ).live('mousewheel',function(e){ $(this).blur(); });ฉันใช้การเบลอแทนการป้องกันค่าเริ่มต้นดังนั้นจึงไม่บล็อกหน้าจากการเลื่อน!
Thibaut Colson

นอกจากนี้ยังดีเกี่ยวกับการเบลอฉันไม่รู้ว่าคุณยังอนุญาตให้เลื่อนหน้าได้ ฉันได้อัปเดตคำตอบแล้ว
Simon Perepelitsa

13
FYI live()เลิกใช้งานแล้ว ตอนนี้คุณควรใช้on(): $(':input[type=number]').on('mousewheel',function(e){ $(this).blur(); });
Saeid Zebardast

3
@SaeidZebardast ความคิดเห็นของคุณสมควรที่จะเป็นคำตอบ
snumpy

สำหรับเบราว์เซอร์ที่ทันสมัยกรุณาใช้เหตุการณ์แทนwheel mousewheelอ้างอิง: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
vee

16

คุณสามารถใช้แอตทริบิวต์HTML onwheel

ตัวเลือกนี้ไม่มีผลกระทบในการเลื่อนดูองค์ประกอบอื่น ๆ ของหน้า

และเพิ่ม Listener สำหรับอินพุตทั้งหมดจะไม่ทำงานในอินพุตที่สร้างแบบไดนามิกด้านหลัง

นอกจากนี้คุณสามารถลบลูกศรอินพุตด้วย 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 - Material 6
Nasiruddin Saiyed


เราสามารถค้นหา CSS นี้ได้จากหลายแหล่ง อย่างไรก็ตาม CSS เป็นเพียงโบนัสเท่านั้น วิธีแก้ปัญหาที่แท้จริงคือแอตทริบิวต์ HTML onwheel ;-)
Maikon Matheus

5
ฉันชอบวิธีนี้! ขอบคุณ ในกรณีของฉันonBlur()ไม่เป็นไปตามที่คาดไว้ ฉันตั้งค่าง่ายๆreturn falseแทนเพื่อ "ไม่ต้องทำอะไรบนวงล้อ" จริงๆ <input type="number" onwheel="return false;">
Daniel

14

@Semyon Perepelitsa

มีทางออกที่ดีกว่านี้ การเบลอจะลบโฟกัสออกจากอินพุตและนั่นคือผลข้างเคียงที่คุณไม่ต้องการ คุณควรใช้ evt.preventDefault แทน ซึ่งจะป้องกันพฤติกรรมเริ่มต้นของอินพุตเมื่อผู้ใช้เลื่อน นี่คือรหัส:

input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(evt){ evt.preventDefault(); })

6
ใช้งานได้ แต่เหตุการณ์จะไม่เป็นฟองดังนั้นหน้าจะไม่เลื่อน มีวิธีรักษาพฤติกรรมเริ่มต้น (เลื่อนหน้า) โดยไม่เบลอหรือไม่?
GuiGS

สำหรับเบราว์เซอร์ที่ทันสมัยกรุณาใช้เหตุการณ์แทนwheel mousewheelอ้างอิง: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
vee

7

ก่อนอื่นคุณต้องหยุดเหตุการณ์ mousewheel โดย:

  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');ก่อนที่จะเบลอจากนั้นผู้พิทักษ์จะตั้งค่าระยะหมดเวลาหาก hadFocs เป็นจริงเท่านั้น
Rob Dawson

3

สำหรับใครก็ตามที่ทำงานกับ React และกำลังมองหาวิธีแก้ปัญหา ฉันพบว่าวิธีที่ง่ายที่สุดคือการใช้ onWheelCapture prop ในองค์ประกอบอินพุตดังนี้:

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


2

คำตอบที่ให้ไว้ใช้ไม่ได้ใน Firefox (Quantum) ต้องเปลี่ยนผู้ฟังเหตุการณ์จากล้อเลื่อนเป็นล้อ:

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

รหัสนี้ใช้ได้กับ Firefox Quantum และ Chrome


2

การเปลี่ยนแปลง typescript

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

ในขณะที่พยายามแก้ปัญหานี้ด้วยตัวเองฉันสังเกตเห็นว่าเป็นไปได้จริงที่จะคงการเลื่อนของหน้าและโฟกัสของข้อมูลเข้าในขณะที่ปิดใช้งานการเปลี่ยนแปลงตัวเลขโดยพยายามที่จะเริ่มเหตุการณ์ที่จับได้อีกครั้งในองค์ประกอบหลักของ<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>ฟิลด์ที่เกี่ยวข้องกับฟิลด์แบบฟอร์มจะเป็นการโฟกัสฟิลด์ อย่างไรก็ตาม“ windowpane” ขององค์ประกอบหลอกที่อยู่เหนือฟิลด์จะปิดกั้นไม่ให้เหตุการณ์ mousewheel เข้าถึงได้

ข้อเสียเปรียบคือปุ่มสปินเนอร์ขึ้น / ลงไม่ทำงานอีกต่อไป แต่คุณบอกว่าคุณได้ลบออกไปแล้ว


ตามทฤษฎีแล้วเราสามารถเรียกคืนเมนูบริบทได้โดยไม่ต้องให้อินพุตถูกโฟกัสก่อน: :hoverสไตล์ไม่ควรเริ่มทำงานเมื่อผู้ใช้เลื่อนเนื่องจากเบราว์เซอร์หลีกเลี่ยงการคำนวณซ้ำระหว่างการเลื่อนด้วยเหตุผลด้านประสิทธิภาพ แต่ฉันไม่ได้ข้ามเบราว์เซอร์ / อุปกรณ์อย่างละเอียด ทดสอบแล้ว


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() }}อินพุตเอง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.