概要:
ここでは、jQueryを使用しないクロスブラウザーのデスクトップおよびモバイル機能を提供し、現在のブラウザーでは不可能な、範囲/スライダーの相互作用に一貫して応答します。基本的に、すべてのブラウザーにIE11のon("change"...
イベント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
リスナーです。リスナーは、範囲/スライダーの値を変更するインタラクションの後に呼び出されますが、その値を変更しないインタラクションの後には呼び出されません。
問題:
2016年6月上旬の時点で、範囲/スライダーの使用に対するブラウザーの反応は異なります。5つのシナリオが関連します。
- 現在のスライダー位置での最初のマウスダウン(またはタッチスタート)
- 新しいスライダー位置での最初のマウスダウン(またはタッチスタート)
- スライダーに沿って1または2を押した後のマウス(またはタッチ)の動き
- スライダーのいずれかの端を1または2過ぎた後のマウス(またはタッチ)の動き
- 最後のマウスアップ(またはタッチエンド)
次の表は、対応する上記のシナリオのどれに関して、少なくとも3つの異なるデスクトップブラウザーの動作が異なるかを示しています。
解決:
このonRangeChange
関数は、範囲/スライダーの相互作用に対する一貫した予測可能なクロスブラウザー応答を提供します。すべてのブラウザが次の表に従って動作するように強制します。
IE11では、コードは本質的にすべてが現状のままで動作することを許可します。つまり"change"
、標準的な方法でイベントが機能することを許可し、"input"
イベントはいずれにせよ発生しないため、無関係です。他のブラウザでは、"change"
イベントは効果的に消音されます(余分なイベントや時々すぐには見えないイベントが発生するのを防ぐため)。加えて"input"
イベントは、範囲/スライダーの値が変更されたときにのみリスナーを起動します。一部のブラウザー(Firefoxなど)では、上記のリストのシナリオ1、4、および5でリスナーが効果的に沈黙するため、これが発生します。
(あなたが本当にどちらのシナリオ1、4および/または5で活性化されるリスナーが必要な場合は、取り入れてみてください可能性が"mousedown"
/ "touchstart"
、"mousemove"
/ "touchmove"
および/または"mouseup"
/ "touchend"
イベントを。そのような解決策は、この答えの範囲を超えています。)
モバイルブラウザの機能:
このコードはデスクトップブラウザでテストしましたが、モバイルブラウザではテストしていません。ただし、このページの別の回答で、 MBourneはここに私の解決策を示しています"...私が見つけたすべてのブラウザー(Winデスクトップ: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では、上記のシナリオ2と3で行AとCの両方の値が変化し、行Bは決して変化しません。
- ChromeとSafariでは、行BとCの値は両方ともシナリオ2と3で変化しますが、行Aはシナリオ5でのみ変化します。
- Firefoxでは、行Aの値はシナリオ5でのみ変更され、行Bは5つすべてのシナリオで変更され、行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
onchange
発砲しません。この問題を見つけたのは、その問題のトラブルシューティングでした。