TÓM LƯỢC:
Tôi cung cấp ở đây một khả năng máy tính để bàn và thiết bị di động đa trình duyệt jQuery để đáp ứng nhất quán các tương tác phạm vi / thanh trượt, một điều không thể có trong các trình duyệt hiện tại. Về cơ bản, nó buộc tất cả các trình duyệt mô phỏng on("change"...
sự kiện của IE11 cho sự kiện on("change"...
hoặc on("input"...
sự kiện của họ . Chức năng mới là ...
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);});
}
... đâu r
là yếu tố đầu vào phạm vi của bạn và f
là người nghe của bạn. Người nghe sẽ được gọi sau bất kỳ tương tác nào thay đổi giá trị phạm vi / thanh trượt nhưng không phải sau các tương tác không thay đổi giá trị đó, bao gồm tương tác chuột hoặc chạm ban đầu ở vị trí thanh trượt hiện tại hoặc khi di chuyển khỏi đầu thanh trượt.
Vấn đề:
Kể từ đầu tháng 6 năm 2016, các trình duyệt khác nhau khác nhau về cách chúng phản ứng với việc sử dụng phạm vi / thanh trượt. Năm kịch bản có liên quan:
- thả chuột ban đầu (hoặc bắt đầu chạm) tại vị trí thanh trượt hiện tại
- xuống chuột ban đầu (hoặc bắt đầu chạm) ở vị trí trượt mới
- bất kỳ chuyển động chuột (hoặc chạm) tiếp theo nào sau 1 hoặc 2 dọc theo thanh trượt
- bất kỳ chuyển động chuột (hoặc chạm) tiếp theo nào sau 1 hoặc 2 qua một trong hai đầu của thanh trượt
- chuột cuối cùng (hoặc touch-end)
Bảng sau đây cho thấy ít nhất ba trình duyệt máy tính để bàn khác nhau về hành vi của chúng đối với kịch bản nào ở trên mà chúng phản ứng:
Giải pháp:
Các onRangeChange
chức năng cung cấp một câu trả lời qua trình duyệt nhất quán và có thể dự đoán tương tác nhiều / trượt. Nó buộc tất cả các trình duyệt hoạt động theo bảng sau:
Trong IE11, mã về cơ bản cho phép mọi thứ hoạt động theo nguyên trạng, tức là nó cho phép "change"
sự kiện hoạt động theo cách tiêu chuẩn của nó và "input"
sự kiện này không liên quan vì dù sao nó cũng không bao giờ phát sinh. Trong các trình duyệt khác, "change"
sự kiện này được tắt tiếng một cách hiệu quả (để ngăn chặn các sự kiện thêm và đôi khi không dễ thấy xảy ra khi bắn). Ngoài ra, "input"
sự kiện chỉ kích hoạt trình nghe của nó khi giá trị của phạm vi / thanh trượt thay đổi. Đối với một số trình duyệt (ví dụ Firefox), điều này xảy ra do trình nghe bị tắt tiếng một cách hiệu quả trong các kịch bản 1, 4 và 5 từ danh sách trên.
(Nếu bạn thực sự yêu cầu người nghe được kích hoạt trong cả kịch bản 1, 4 và / hoặc 5, bạn có thể thử kết hợp "mousedown"
/ "touchstart"
, "mousemove"
/ "touchmove"
và / hoặc "mouseup"
/ "touchend"
sự kiện. Giải pháp như vậy nằm ngoài phạm vi của câu trả lời này.)
Chức năng trong trình duyệt di động:
Tôi đã thử nghiệm mã này trong các trình duyệt máy tính để bàn nhưng không phải trong bất kỳ trình duyệt di động nào. Tuy nhiên, trong một câu trả lời khác trên trang này, MBourne đã chỉ ra rằng giải pháp của tôi ở đây "... dường như hoạt động trong mọi trình duyệt tôi có thể tìm thấy (Win desktop: IE, Chrome, Opera, FF; Android Chrome, Opera và FF, iOS Safari) " . (Cảm ơn MBourne.)
Sử dụng:
Để sử dụng giải pháp này, hãy bao gồm onRangeChange
hàm từ tóm tắt ở trên (đơn giản hóa / rút gọn) hoặc đoạn mã trình diễn bên dưới (giống hệt về chức năng nhưng tự giải thích nhiều hơn) trong mã của riêng bạn. Gọi nó như sau:
onRangeChange(myRangeInputElmt, myListener);
đâu myRangeInputElmt
là <input type="range">
phần tử DOM mong muốn của bạn và myListener
là hàm nghe / xử lý mà bạn muốn gọi "change"
các sự kiện giống như.
Trình nghe của bạn có thể không tham số nếu muốn hoặc có thể sử dụng event
tham số, tức là một trong hai cách sau sẽ hoạt động, tùy thuộc vào nhu cầu của bạn:
var myListener = function() {...
hoặc là
var myListener = function(evt) {...
(Loại bỏ trình nghe sự kiện khỏi thành input
phần (ví dụ: sử dụng removeEventListener
) không được đề cập trong câu trả lời này.)
Mô tả demo:
Trong đoạn mã dưới đây, hàm onRangeChange
cung cấp giải pháp phổ quát. Phần còn lại của mã chỉ là một ví dụ để chứng minh việc sử dụng nó. Bất kỳ biến nào bắt đầu bằng my...
không liên quan đến giải pháp phổ quát và chỉ hiện diện vì lợi ích của bản demo.
Các chương trình giới thiệu các giá trị phạm vi / trượt cũng như số lần tiêu chuẩn "change"
, "input"
và tùy chỉnh "onRangeChange"
sự kiện này đã bị sa thải (hàng A, B và C tương ứng). Khi chạy đoạn mã này trong các trình duyệt khác nhau, hãy lưu ý những điều sau khi bạn tương tác với phạm vi / thanh trượt:
- Trong IE11, các giá trị ở hàng A và C đều thay đổi trong các kịch bản 2 và 3 ở trên trong khi hàng B không bao giờ thay đổi.
- Trong Chrome và Safari, các giá trị ở hàng B và C đều thay đổi trong kịch bản 2 và 3 trong khi hàng A chỉ thay đổi cho kịch bản 5.
- Trong Firefox, giá trị trong hàng A chỉ thay đổi cho kịch bản 5, hàng B thay đổi cho tất cả năm kịch bản và hàng C chỉ thay đổi cho các kịch bản 2 và 3.
- Trong tất cả các trình duyệt trên, các thay đổi trong hàng C (giải pháp được đề xuất) là giống hệt nhau, tức là chỉ dành cho các kịch bản 2 và 3.
Mã giới thiệu:
// 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>
Tín dụng:
Mặc dù việc thực hiện ở đây phần lớn là của riêng tôi, nó được lấy cảm hứng từ câu trả lời của MBourne . Câu trả lời khác cho rằng các sự kiện "đầu vào" và "thay đổi" có thể được hợp nhất và mã kết quả sẽ hoạt động trong cả trình duyệt máy tính để bàn và thiết bị di động. Tuy nhiên, mã trong câu trả lời đó dẫn đến các sự kiện "phụ" bị ẩn được kích hoạt, trong đó bản thân nó có vấn đề và các sự kiện được bắn khác nhau giữa các trình duyệt, một vấn đề nữa. Việc thực hiện của tôi ở đây giải quyết những vấn đề đó.
Từ khóa:
Các sự kiện thanh trượt phạm vi loại đầu vào JavaScript thay đổi khả năng tương thích trình duyệt đầu vào trình duyệt chéo trên máy tính để bàn không có jQuery
onchange
không bắn. Đó là trong việc khắc phục sự cố mà tôi tìm thấy câu hỏi này.