เหตุการณ์ onchange บนอินพุต type = range ไม่ได้ถูกเรียกใช้ใน firefox ขณะลาก


252

เมื่อฉันเล่นด้วย<input type="range">Firefox จะทริกเกอร์เหตุการณ์ onchange เฉพาะเมื่อเราเลื่อนตัวเลื่อนไปยังตำแหน่งใหม่ที่ Chrome และคนอื่น ๆ เรียกใช้เหตุการณ์ onchange ในขณะที่ลากตัวเลื่อน

ฉันจะทำให้มันเกิดขึ้นเมื่อลากใน Firefox ได้อย่างไร

function showVal(newVal){
    document.getElementById("valBox").innerHTML=newVal;
}
<span id="valBox"></span>
<input type="range" min="5" max="10" step="1" onchange="showVal(this.value)">


4
หากองค์ประกอบช่วงมีโฟกัสคุณสามารถเลื่อนแถบเลื่อนโดยใช้ปุ่มลูกศร และในกรณีนั้นก็เช่นกันonchangeไฟไม่ได้ มันเป็นการแก้ไขปัญหาที่ฉันพบคำถามนี้
Sildoreth

คำตอบ:


452

เห็นได้ชัดว่า Chrome และ Safari ผิด: onchangeควรถูกเรียกใช้เมื่อผู้ใช้ปล่อยเมาส์ ในการรับการอัปเดตอย่างต่อเนื่องคุณควรใช้oninputกิจกรรมซึ่งจะบันทึกการอัปเดตสดใน Firefox, Safari และ Chrome ทั้งจากเมาส์และแป้นพิมพ์

อย่างไรก็ตามoninputไม่ได้รับการสนับสนุนใน IE10 ดังนั้นทางออกที่ดีที่สุดของคุณคือการรวมตัวจัดการเหตุการณ์สองแบบดังนี้:

<span id="valBox"></span>
<input type="range" min="5" max="10" step="1" 
   oninput="showVal(this.value)" onchange="showVal(this.value)">

ตรวจสอบกระทู้ Bugzillaนี้สำหรับข้อมูลเพิ่มเติม


113
หรือ$("#myelement").on("input change", function() { doSomething(); });กับ jQuery
Alex Vang

19
เพิ่งทราบว่าด้วยวิธีนี้ในโครเมี่ยมคุณจะได้รับสองสายไปยังตัวจัดการ (หนึ่งต่อเหตุการณ์) ดังนั้นหากคุณสนใจมันคุณจะต้องป้องกันมัน
Jaime

3
ฉันมีปัญหากับเหตุการณ์ 'เปลี่ยน' ที่ไม่ได้ยิงในมือถือ chrome (v34) แต่การเพิ่ม 'อินพุต' ลงในสมการได้แก้ไขให้ฉันแล้วในขณะที่ไม่มีผลกระทบที่เป็นอันตรายที่อื่น
brins0

7
@ Jaime: " ถ้าคุณเป็นอย่างนั้นคุณต้องป้องกันมันด้วย " ฉันจะทำยังไงดี

2
น่าเศร้าที่onchange()ไม่ได้ทำงานบนเว็บมือถือเช่นและAndroid Chrome iOS Safariข้อเสนอแนะทางเลือกใด ๆ
Alston

41

สรุป:

ฉันมอบความสามารถแบบเดสก์ท็อปและเบราว์เซอร์ข้ามมือถือที่ไม่ใช่ jQuery เพื่อตอบสนองต่อการโต้ตอบช่วง / ตัวเลื่อนอย่างต่อเนื่องซึ่งเป็นสิ่งที่เป็นไปไม่ได้ในเบราว์เซอร์ปัจจุบัน มันบังคับให้เบราว์เซอร์ทั้งหมดเลียนแบบon("change"...เหตุการณ์ของ IE11 ไม่ว่าจะเป็นของพวกเขาon("change"...หรือon("input"...เหตุการณ์ ฟังก์ชั่นใหม่คือ ...

function onRangeChange(r,f) {
  var n,c,m;
  r.addEventListener("input",function(e){n=1;c=e.target.value;if(c!=m)f(e);m=c;});
  r.addEventListener("change",function(e){if(!n)f(e);});
}

... rองค์ประกอบการป้อนข้อมูลของคุณอยู่ที่ไหนและfเป็นผู้ฟังของคุณ ผู้ฟังจะถูกเรียกใช้หลังจากการโต้ตอบใด ๆ ที่เปลี่ยนค่าช่วง / ตัวเลื่อน แต่ไม่ใช่หลังจากการโต้ตอบที่ไม่เปลี่ยนค่านั้นรวมถึงเมาส์เริ่มต้นหรือการโต้ตอบแบบสัมผัสที่ตำแหน่งแถบเลื่อนปัจจุบัน

ปัญหา:

ตั้งแต่ต้นเดือนมิถุนายน 2559 เบราว์เซอร์ที่แตกต่างกันมีความแตกต่างกันในแง่ของการตอบสนองต่อการใช้งานช่วง / ตัวเลื่อน ห้าสถานการณ์ที่เกี่ยวข้อง:

  1. การเลื่อนเมาส์เริ่มต้น (หรือแตะเริ่ม) ที่ตำแหน่งตัวเลื่อนปัจจุบัน
  2. การเลื่อนเมาส์เริ่มต้น (หรือแตะเริ่ม) ที่ตำแหน่งตัวเลื่อนใหม่
  3. การเคลื่อนไหวของเมาส์ (หรือสัมผัส) ใด ๆ ที่ตามมาหลังจาก 1 หรือ 2 ไปตามแถบเลื่อน
  4. การเคลื่อนไหวของเมาส์ (หรือสัมผัส) ใด ๆ ที่ตามมาหลังจากผ่านไป 1 หรือ 2 ครั้งสุดท้ายทั้งสองด้านของแถบเลื่อน
  5. การเลื่อนเมาส์ครั้งสุดท้าย (หรือการสัมผัส)

ตารางต่อไปนี้แสดงให้เห็นว่าเบราว์เซอร์เดสก์ท็อปที่แตกต่างกันอย่างน้อยสามตัวแตกต่างกันอย่างไรในพฤติกรรมที่เกี่ยวข้องกับสถานการณ์ข้างต้น

ตารางแสดงความแตกต่างของเบราว์เซอร์เกี่ยวกับกิจกรรมที่พวกเขาตอบสนองและเมื่อ

สารละลาย:

onRangeChangeฟังก์ชั่นให้การตอบสนองที่เบราว์เซอร์ที่สอดคล้องกันและคาดการณ์ในช่วง / ปฏิสัมพันธ์เลื่อน มันบังคับให้เบราว์เซอร์ทั้งหมดทำงานตามตารางต่อไปนี้:

ตารางแสดงพฤติกรรมของเบราว์เซอร์ทั้งหมดโดยใช้วิธีแก้ไขที่เสนอ

ใน IE11 รหัสนั้นอนุญาตให้ทุกอย่างทำงานตามสถานะเดิมคืออนุญาตให้"change"เหตุการณ์ทำงานในลักษณะมาตรฐานและ"input"เหตุการณ์ไม่เกี่ยวข้องเนื่องจากไม่เคยเกิดไฟเลย ในเบราว์เซอร์อื่น"change"กิจกรรมจะถูกปิดเสียงอย่างมีประสิทธิภาพ (เพื่อป้องกันเหตุการณ์พิเศษและบางครั้งไม่พร้อมที่จะยิง) นอกจากนี้"input"เหตุการณ์ยิงผู้ฟังเมื่อค่าของช่วง / แถบเลื่อนเปลี่ยนไป สำหรับบางเบราว์เซอร์ (เช่น Firefox) สิ่งนี้เกิดขึ้นเนื่องจากผู้ฟังถูกปิดเสียงอย่างมีประสิทธิภาพในสถานการณ์ 1, 4 และ 5 จากรายการด้านบน

(ถ้าคุณต้องการให้ผู้ฟังเปิดใช้งานจริงในสถานการณ์ 1, 4 และ / หรือ 5 คุณสามารถลองใช้การรวม"mousedown"/ "touchstart", "mousemove"/ "touchmove"และ / หรือ"mouseup"/ "touchend"เหตุการณ์การแก้ปัญหาดังกล่าวอยู่นอกเหนือขอบเขตของคำตอบนี้)

ฟังก์ชั่นในเบราว์เซอร์มือถือ:

ฉันทดสอบโค้ดนี้ในเบราว์เซอร์เดสก์ท็อป แต่ไม่ได้ใช้กับเบราว์เซอร์มือถือใด ๆ อย่างไรก็ตามในคำตอบอื่นในหน้านี้ MBourne แสดงให้เห็นว่าวิธีการแก้ปัญหาของฉันที่นี่"... ดูเหมือนจะทำงานในทุกเบราว์เซอร์ที่ฉันสามารถหาได้ (Win desktop: IE, Chrome, Opera, FF; Android Chrome, Opera และ FF, iOS Safari) " . (ขอบคุณ MBourne)

การใช้งาน:

ในการใช้โซลูชันนี้ให้รวมonRangeChangeฟังก์ชั่นจากข้อมูลสรุปด้านบน (แบบย่อ / ย่อขนาด) หรือตัวอย่างข้อมูลโค้ดด้านล่าง (เหมือนฟังก์ชั่นที่เหมือนกัน แต่มีการอธิบายตนเองมากกว่า) ในรหัสของคุณ เรียกใช้ดังนี้:

onRangeChange(myRangeInputElmt, myListener);

ที่myRangeInputElmtเป็น<input type="range">องค์ประกอบ DOM ที่คุณต้องการและmyListenerเป็นฟัง / ฟังก์ชั่นการจัดการที่คุณต้องการเรียกใช้เมื่อ"change"เหตุการณ์เหมือน

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

var myListener = function() {...

หรือ

var myListener = function(evt) {...

(การลบผู้ฟังเหตุการณ์ออกจากinputองค์ประกอบ (เช่นใช้removeEventListener) ไม่ได้ระบุไว้ในคำตอบนี้)

คำอธิบายการสาธิต:

ในข้อมูลโค้ดด้านล่างฟังก์ชั่นonRangeChangeให้บริการโซลูชั่นสากล ส่วนที่เหลือของรหัสเป็นเพียงตัวอย่างเพื่อแสดงให้เห็นถึงการใช้งาน ตัวแปรใด ๆ ที่ขึ้นต้นด้วยmy...ไม่เกี่ยวข้องกับโซลูชันสากลและนำเสนอเพื่อการสาธิตเท่านั้น

การแสดงสาธิตค่าช่วง / เลื่อนเช่นเดียวกับจำนวนครั้งที่มาตรฐาน"change", "input"และกำหนดเอง"onRangeChange"เหตุการณ์ยิง (แถว A, B และ C ตามลำดับ) เมื่อเรียกใช้ตัวอย่างข้อมูลนี้ในเบราว์เซอร์ที่แตกต่างกันให้สังเกตสิ่งต่อไปนี้ในขณะที่คุณโต้ตอบกับช่วง / ตัวเลื่อน:

  • ใน IE11 ค่าในแถว A และ C ทั้งสองเปลี่ยนแปลงในสถานการณ์ 2 และ 3 ข้างต้นในขณะที่แถว B ไม่เปลี่ยนแปลง
  • ใน Chrome และ Safari ค่าในแถว B และ C ทั้งคู่จะเปลี่ยนไปในสถานการณ์ที่ 2 และ 3 ในขณะที่แถว A เปลี่ยนแปลงเฉพาะในสถานการณ์ที่ 5 เท่านั้น
  • ใน Firefox ค่าในแถว A จะเปลี่ยนเฉพาะสำหรับสถานการณ์ 5, แถว B เปลี่ยนสำหรับทั้งห้าสถานการณ์และแถว C เปลี่ยนแปลงเฉพาะสำหรับสถานการณ์ 2 และ 3 เท่านั้น
  • ในเบราว์เซอร์ทั้งหมดข้างต้นการเปลี่ยนแปลงในแถว C (โซลูชันที่เสนอ) เหมือนกันนั่นคือเฉพาะสำหรับสถานการณ์ 2 และ 3

รหัสตัวอย่าง:

// main function for emulating IE11's "change" event:

function onRangeChange(rangeInputElmt, listener) {

  var inputEvtHasNeverFired = true;

  var rangeValue = {current: undefined, mostRecent: undefined};
  
  rangeInputElmt.addEventListener("input", function(evt) {
    inputEvtHasNeverFired = false;
    rangeValue.current = evt.target.value;
    if (rangeValue.current !== rangeValue.mostRecent) {
      listener(evt);
    }
    rangeValue.mostRecent = rangeValue.current;
  });

  rangeInputElmt.addEventListener("change", function(evt) {
    if (inputEvtHasNeverFired) {
      listener(evt);
    }
  }); 

}

// example usage:

var myRangeInputElmt = document.querySelector("input"          );
var myRangeValPar    = document.querySelector("#rangeValPar"   );
var myNumChgEvtsCell = document.querySelector("#numChgEvtsCell");
var myNumInpEvtsCell = document.querySelector("#numInpEvtsCell");
var myNumCusEvtsCell = document.querySelector("#numCusEvtsCell");

var myNumEvts = {input: 0, change: 0, custom: 0};

var myUpdate = function() {
  myNumChgEvtsCell.innerHTML = myNumEvts["change"];
  myNumInpEvtsCell.innerHTML = myNumEvts["input" ];
  myNumCusEvtsCell.innerHTML = myNumEvts["custom"];
};

["input", "change"].forEach(function(myEvtType) {
  myRangeInputElmt.addEventListener(myEvtType,  function() {
    myNumEvts[myEvtType] += 1;
    myUpdate();
  });
});

var myListener = function(myEvt) {
  myNumEvts["custom"] += 1;
  myRangeValPar.innerHTML = "range value: " + myEvt.target.value;
  myUpdate();
};

onRangeChange(myRangeInputElmt, myListener);
table {
  border-collapse: collapse;  
}
th, td {
  text-align: left;
  border: solid black 1px;
  padding: 5px 15px;
}
<input type="range"/>
<p id="rangeValPar">range value: 50</p>
<table>
  <tr><th>row</th><th>event type                     </th><th>number of events    </th><tr>
  <tr><td>A</td><td>standard "change" events         </td><td id="numChgEvtsCell">0</td></tr>
  <tr><td>B</td><td>standard "input" events          </td><td id="numInpEvtsCell">0</td></tr>
  <tr><td>C</td><td>new custom "onRangeChange" events</td><td id="numCusEvtsCell">0</td></tr>
</table>

เครดิต:

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

คำสำคัญ:

เหตุการณ์ตัวเลื่อนช่วงประเภทอินพุต JavaScript เปลี่ยนความเข้ากันได้ของเบราว์เซอร์สำหรับการป้อนข้อมูลข้ามเบราว์เซอร์เดสก์ท็อปมือถือ no-jQuery


31

ฉันโพสต์สิ่งนี้เป็นคำตอบเพราะสมควรที่จะเป็นคำตอบของตัวเองมากกว่าความคิดเห็นภายใต้คำตอบที่มีประโยชน์น้อยกว่า ฉันพบว่าวิธีนี้ดีกว่าคำตอบที่ยอมรับได้เนื่องจากสามารถเก็บ js ทั้งหมดในไฟล์แยกต่างหากจาก HTML

ตอบโดย Jamrelian ในความคิดเห็นของเขาภายใต้คำตอบที่ยอมรับ

$("#myelement").on("input change", function() {
    //do something
});

เพียงแค่ตระหนักถึงความคิดเห็นนี้โดยไจแม้ว่า

เพิ่งทราบว่าด้วยวิธีนี้ในโครเมี่ยมคุณจะได้รับสองสายไปยังตัวจัดการ (หนึ่งต่อเหตุการณ์) ดังนั้นหากคุณสนใจมันคุณจะต้องป้องกันมัน

ในขณะที่มันจะยิงเหตุการณ์เมื่อคุณหยุดเลื่อนเมาส์แล้วอีกครั้งเมื่อคุณปล่อยปุ่มเมาส์

ปรับปรุง

เกี่ยวข้องกับchangeเหตุการณ์และinputเหตุการณ์ที่ทำให้ฟังก์ชันการทำงานทริกเกอร์สองครั้งนี่เป็นเรื่องที่ไม่ใช่ปัญหา

หากคุณมีฟังก์ชั่นการปิดไฟinputมันไม่น่าเป็นไปได้อย่างมากที่จะมีปัญหาเมื่อchangeไฟเริ่มขึ้น

inputยิงอย่างรวดเร็วเมื่อคุณลากตัวเลื่อนอินพุตช่วง ความกังวลเกี่ยวกับการเรียกใช้ฟังก์ชันการยิงอีกครั้งในตอนท้ายก็เหมือนกับการกังวลเกี่ยวกับน้ำหยดเดียวเมื่อเปรียบเทียบกับมหาสมุทรของน้ำที่เป็นinputเหตุการณ์

เหตุผลในการรวมchangeเหตุการณ์ทั้งหมดนั้นก็เพื่อความเข้ากันได้ของเบราว์เซอร์ (ส่วนใหญ่จะใช้กับ IE)


บวก 1 สำหรับทางออกเดียวที่ทำงานกับ internet explorer !! คุณทดสอบบนเบราว์เซอร์อื่นด้วยหรือไม่?
เจสสิก้า

1
มัน jQuery ดังนั้นโอกาสที่จะไม่ทำงานก็ค่อนข้างต่ำ ฉันไม่ได้เห็นมันใช้งานไม่ได้ทุกที่ มันใช้งานได้บนมือถือซึ่งยอดเยี่ยมมาก
Daniel Tonon

30

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

คำตอบเดิม:

สรุป: โซลูชันข้ามเบราว์เซอร์ JavaScript ธรรมดา (เช่น no-jQuery) เพื่ออนุญาตให้ป้อนค่าช่วงการอ่านโดยไม่ต้องใช้on('input'...และ / หรือon('change'...ที่ทำงานไม่สอดคล้องกันระหว่างเบราว์เซอร์

ณ วันนี้ (ปลายเดือนกุมภาพันธ์ 2559) ยังมีความไม่สอดคล้องกันของเบราว์เซอร์ดังนั้นฉันจึงเสนอวิธีแก้ปัญหาใหม่ที่นี่

ปัญหา: เมื่อใช้การป้อนช่วงเช่นตัวเลื่อนon('input'...จะให้ค่าช่วงที่อัปเดตอย่างต่อเนื่องใน Mac และ Windows Firefox, Chrome และ Opera รวมถึง Mac Safari ในขณะที่on('change'...รายงานเฉพาะค่าช่วงเมื่อเลื่อนเมาส์ขึ้น ในทางตรงกันข้ามใน Internet Explorer (v11) on('input'...ไม่ทำงานเลยและon('change'...มีการปรับปรุงอย่างต่อเนื่อง

ฉันรายงานที่นี่ 2 กลยุทธ์เพื่อรับการรายงานค่าช่วงต่อเนื่องที่เหมือนกันในทุกเบราว์เซอร์ที่ใช้ vanilla JavaScript (เช่นไม่มี jQuery) โดยใช้เหตุการณ์เมาส์วางเมาส์, มูสซีมูฟและ (อาจ)

กลยุทธ์ที่ 1: สั้นลง แต่มีประสิทธิภาพน้อยลง

หากคุณต้องการรหัสที่สั้นกว่ารหัสที่มีประสิทธิภาพมากขึ้นคุณสามารถใช้วิธีที่ 1 ซึ่งใช้ mousesdown และ mousemove แต่ไม่ใช่ mouseup สิ่งนี้จะอ่านแถบเลื่อนได้ตามต้องการ แต่ยังคงทำงานต่อโดยไม่จำเป็นระหว่างการเลื่อนเมาส์ผ่านเหตุการณ์แม้ว่าจะไม่ได้คลิกผู้ใช้และจะไม่ลากตัวเลื่อน มันเป็นหลักอ่านค่าช่วงทั้งหลัง mousedown 'และในช่วง 'mousemove' requestAnimationFrameเหตุการณ์ล่าช้าเล็กน้อยแต่ละใช้

var rng = document.querySelector("input");

read("mousedown");
read("mousemove");
read("keydown"); // include this to also allow keyboard control

function read(evtType) {
  rng.addEventListener(evtType, function() {
    window.requestAnimationFrame(function () {
      document.querySelector("div").innerHTML = rng.value;
      rng.setAttribute("aria-valuenow", rng.value); // include for accessibility
    });
  });
}
<div>50</div><input type="range"/>

กลยุทธ์ที่ 2: อีกต่อไป แต่มีประสิทธิภาพมากกว่า

หากคุณต้องการรหัสที่มีประสิทธิภาพมากขึ้นและสามารถทนต่อความยาวของรหัสได้อีกต่อไปคุณสามารถใช้วิธีแก้ไขปัญหาต่อไปนี้ซึ่งใช้ mousedown, mousemove และ mouseup สิ่งนี้จะอ่านตัวเลื่อนได้ตามต้องการ แต่จะหยุดอ่านอย่างเหมาะสมทันทีที่ปล่อยปุ่มเมาส์ ความแตกต่างที่สำคัญคือจะเริ่มฟัง 'มูสมูฟ' หลังจาก 'มูสทาวน์' เท่านั้นและจะหยุดฟัง 'มูสมูฟ' หลังจาก 'เมาส์'

var rng = document.querySelector("input");

var listener = function() {
  window.requestAnimationFrame(function() {
    document.querySelector("div").innerHTML = rng.value;
  });
};

rng.addEventListener("mousedown", function() {
  listener();
  rng.addEventListener("mousemove", listener);
});
rng.addEventListener("mouseup", function() {
  rng.removeEventListener("mousemove", listener);
});

// include the following line to maintain accessibility
// by allowing the listener to also be fired for
// appropriate keyboard events
rng.addEventListener("keydown", listener);
<div>50</div><input type="range"/>

การสาธิต: คำอธิบายที่สมบูรณ์ยิ่งขึ้นเกี่ยวกับความต้องการและการนำไปใช้งานการแก้ไขปัญหาข้างต้น

รหัสต่อไปนี้แสดงให้เห็นถึงแง่มุมต่าง ๆ ของกลยุทธ์นี้ คำอธิบายถูกฝังอยู่ในการสาธิต:


ข้อมูลที่ดีจริงๆ บางทีเพิ่มเหตุการณ์สัมผัสบางครั้ง? touchmoveควรจะเพียงพอและฉันคิดว่ามันสามารถได้รับการปฏิบัติเหมือนmousemoveในกรณีนี้
Nick

@ คลิกโปรดดูคำตอบอื่น ๆ ของฉันในหน้านี้เพื่อดูวิธีแก้ไขปัญหาอื่น ๆ
Andrew Willems

นี่ไม่ใช่คำตอบที่สามารถเข้าถึงได้เนื่องจากการนำทางแป้นพิมพ์จะไม่ยิงเหตุการณ์เนื่องจากเมาส์เป็นศูนย์กลาง
LocalPCGuy

@LocalPCGuy คุณพูดถูก คำตอบของฉันทำให้ความสามารถในการควบคุมคีย์บอร์ดของแถบเลื่อนแตกในตัว ฉันได้อัปเดตรหัสเพื่อคืนค่าการควบคุมคีย์บอร์ด หากคุณทราบวิธีอื่นใดที่รหัสของฉันใช้สำหรับการเข้าถึงในตัวแบ่งให้ฉันทราบ
Andrew Willems

7

โซลูชันของ Andrew Willem ไม่สามารถใช้งานกับอุปกรณ์พกพาได้

นี่คือการดัดแปลงโซลูชันที่สองของเขาที่ทำงานใน Edge, IE, Opera, FF, Chrome, iOS Safari และอุปกรณ์เทียบเท่ามือถือ (ที่ฉันทดสอบได้):

อัปเดต 1: ลบส่วน "requestAnimationFrame" ออกเนื่องจากฉันยอมรับว่าไม่จำเป็น:

var listener = function() {
  // do whatever
};

slider1.addEventListener("input", function() {
  listener();
  slider1.addEventListener("change", listener);
});
slider1.addEventListener("change", function() {
  listener();
  slider1.removeEventListener("input", listener);
}); 

อัปเดต 2: คำตอบที่ได้รับการปรับปรุงล่าสุดของ Andrew เมื่อวันที่ 2 มิถุนายน 2559

ขอบคุณแอนดรู - ที่ใช้งานได้กับทุกเบราว์เซอร์ที่ฉันพบ (ชนะเดสก์ท็อป: IE, Chrome, Opera, FF; Android Chrome, Opera และ FF, iOS Safari)

อัปเดต 3: โซลูชัน if ("oninput in slider)

ต่อไปนี้ดูเหมือนว่าจะทำงานได้กับเบราว์เซอร์ทั้งหมดข้างต้น (ฉันไม่สามารถหาแหล่งต้นฉบับได้ในตอนนี้) ฉันใช้สิ่งนี้ แต่ต่อมามันล้มเหลวใน IE ดังนั้นฉันจึงไปหาแหล่งอื่นดังนั้นฉันจึงสิ้นสุดที่นี่

if ("oninput" in slider1) {
    slider1.addEventListener("input", function () {
        // do whatever;
    }, false);
}

แต่ก่อนที่ฉันจะตรวจสอบวิธีการแก้ปัญหาของคุณฉันสังเกตเห็นว่านี่ทำงานได้อีกครั้งใน IE - อาจมีข้อขัดแย้งอื่น ๆ


1
ฉันยืนยันว่าโซลูชันของคุณใช้งานได้ในเบราว์เซอร์เดสก์ท็อปที่หลากหลายสองตัว ได้แก่ Mac Firefox และ Windows IE11 ฉันไม่สามารถตรวจสอบความเป็นไปได้ทางมือถือเป็นการส่วนตัว แต่นี่ดูเหมือนจะเป็นการอัปเดตที่ยอดเยี่ยมสำหรับคำตอบของฉันที่จะขยายรวมอุปกรณ์มือถือ (ฉันสมมติว่า "อินพุต" และ "เปลี่ยน" ยอมรับทั้งการป้อนข้อมูลเมาส์บนระบบเดสก์ท็อปและการป้อนข้อมูลแบบสัมผัสบนระบบมือถือ) งานที่ดีมากที่ควรจะใช้งานได้ในวงกว้างและคุ้มค่าในการรับรู้และการนำไปใช้!
Andrew Willems

1
หลังจากขุดต่อไปฉันได้ตระหนักว่าทางออกของคุณมีข้อบกพร่องหลายประการ ก่อนอื่นฉันเชื่อว่าการร้องขอ AnimationFrame นั้นไม่จำเป็น ประการที่สองโค้ดใช้งานเหตุการณ์พิเศษ (อย่างน้อย 3 เหตุการณ์เช่น mouseup ในบางเบราว์เซอร์) ประการที่สามเหตุการณ์ที่เกิดขึ้นจริงนั้นแตกต่างกันระหว่างเบราว์เซอร์บางตัว ฉันจึงให้คำตอบแยกต่างหากจากแนวคิดเริ่มต้นของคุณในการใช้การรวมกันของ "อินพุต" และ "เปลี่ยน" เหตุการณ์ให้เครดิตกับแรงบันดาลใจดั้งเดิม
Andrew Willems

2

สำหรับพฤติกรรมข้ามเบราว์เซอร์ที่ดีและรหัสที่เข้าใจได้ดีที่สุดคือการใช้แอตทริบิวต์ onchange ร่วมกับแบบฟอร์ม:

function showVal(){
  valBox.innerHTML = inVal.value;

}
<form onchange="showVal()">
  <input type="range" min="5" max="10" step="1" id="inVal">
  </form>

<span id="valBox">
  </span>

เช่นเดียวกันโดยใช้oninputค่าจะถูกเปลี่ยนโดยตรง

function showVal(){
  valBox.innerHTML = inVal.value;

}
<form oninput="showVal()">
  <input type="range" min="5" max="10" step="1" id="inVal">
  </form>

<span id="valBox">
  </span>


0

อีกแนวทางหนึ่ง - เพียงแค่ตั้งค่าสถานะบนองค์ประกอบการส่งสัญญาณว่าควรจัดการประเภทของเหตุการณ์:

function setRangeValueChangeHandler(rangeElement, handler) {
    rangeElement.oninput = (event) => {
        handler(event);
        // Save flag that we are using onInput in current browser
        event.target.onInputHasBeenCalled = true;
    };

    rangeElement.onchange = (event) => {
        // Call only if we are not using onInput in current browser
        if (!event.target.onInputHasBeenCalled) {
            handler(event);
        }
    };
}

-3

คุณสามารถใช้เหตุการณ์ "ondrag" ของ JavaScript เพื่อเริ่มต้นอย่างต่อเนื่อง ดีกว่า "อินพุต" เนื่องจากเหตุผลดังต่อไปนี้:

  1. รองรับเบราว์เซอร์

  2. สามารถแยกความแตกต่างระหว่างเหตุการณ์ "ondrag" และ "เปลี่ยน" "อินพุต" ไฟสำหรับทั้งการลากและการเปลี่ยนแปลง

ใน jQuery:

$('#sample').on('drag',function(e){

});

การอ้างอิง: http://www.w3schools.com/TAgs/ev_ondrag.asp

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