更新:
私は、同じ関数に対してクリック イベントとタッチエンド イベントの両方を使用する実装に取り組んでおり、型が変更された場合、関数はイベントを効果的にブロックします。私の目標は、アプリケーション インターフェイスの応答性を高めることでした。イベント開始から UI フィードバック ループまでの時間を短縮したかったのです。
この実装が機能するためには、関連するすべてのイベントが「クリック」と「タッチエンド」に追加されていることを前提としています。これにより、両方のイベントを実行する必要があるが、タイプが異なる場合に、1 つの要素がイベント バブリングを奪われるのを防ぎます。
これは、デモンストレーションのために簡略化した軽量の API ベースの実装です。折りたたみ要素で機能を使用する方法を示します。
var tv = {
/**
* @method eventValidator()
* @desc responsible for validating event of the same type.
* @param {Object} e - event object
* @param {Object} element - element event cache
* @param {Function} callback - callback to invoke for events of the same type origin
* @param {Object} [context] - context to pass to callback function
* @param {Array} [args] - arguments array to pass in with context. Requires context to be passed
* @return {Object} - new event cache
*/
eventValidator: function(e, element, callback, context, args){
if(element && element.type && element.type !== e.type){
e.stopPropagation();
e.preventDefault();
return tv.createEventCacheObj({}, true);
} else {
element = tv.createEventCacheObj(e);
(typeof context === "object" ? callback.apply(context, args) : callback());
return element;
}
},
/**
* @method createEventCacheObj()
* @param {Object} event - event object
* @param {String} [event.type] - event type
* @param {Number} [event.timeStamp] - time of event in MS since load
* @param {Boolean} [reset=false] - flag to reset the object
* @returns {{type: *, time: string}}
*/
createEventCacheObj: function (event, reset){
if(typeof reset !== 'boolean') reset = false;
return {
type: !reset ? event.type : null,
time: !reset ? (event.timeStamp).toFixed(2): null
};
}
};
// Here is where the magic happens
var eventCache = [];
var pos = 0;
var $collapses = document.getElementsByClassName('tv-collapse__heading');
Array.prototype.forEach.call($collapses, function(ele){
ele.addEventListener('click', toggleCollapse);
ele.addEventListener('touchend', toggleCollapse);
// Cache mechanism
ele.setAttribute('data-event-cache', String(pos++));
});
/**
* @func toggleCollapse()
* @param {Object} e - event object
* @desc responsible for toggling the state of a collapse element
*/
function toggleCollapse(e){
eventCache[pos] = tv.eventValidator(e, eventCache[pos], function(){
// Any event which isn't blocked will run the callback and its content
// the context and arguments of the anonymous function match the event function context and arguments (assuming they are passed using the last two parameters of tv.eventValidator)
}, this, arguments);
}
元の回答:
これは、Rafael Fragoso の回答 (純粋な JS) を変更した回答です。
(function(){
button = document.getElementById('sayHi');
button.addEventListener('touchstart', ohHai);
button.addEventListener('click', ohHai);
function ohHai(event){
event.stopPropagation();
event.preventDefault();
console.log('ohHai is:', event.type);
};
})();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SO - Answer</title>
</head>
<body>
<button id="sayHi">Anyone there?</button>
</body>
</html>
次のスニペットを実行し、出力に注意してください。
- 電話
- タブレット
- タブレット (デスクトップ モード - 該当する場合)
- デスクトップ
- デスクトップ (タッチスクリーン - 該当する場合)
重要なのは、連続するイベントの起動を停止していることです。モバイル ブラウザは、タッチが発生したときにクリックをエミュレートするために最善を尽くします。タッチスタートからクリックまでの後に発生するすべてのイベントを説明している、しばらく前に見た記事へのリンクを見つけることができれば幸いです。(ダブルタップとクリックが実際に発火するまでの300ミリ秒の遅延を探していました)。
タッチおよびマウス デバイス
Surface Pro とタッチスクリーン付きの Windows 10 デスクトップを使用して、いくつかのテストを実行しました。私が見つけたのは、あなたが疑うように、両方ともイベントをトリガーしたことです。タッチの場合は touchstart、トラックパッド、マウス、スタイリストの場合はクリックです。興味深いのは、ボタン上ではなく近くにあるタッチ イベントが、タッチ イベントなしでクリック イベントをトリガーすることです。Windows 10 の組み込み機能は、半径内で最も近いノードを探し、ノードが見つかった場合、マウス ベースのイベントを発生させるようです。
同じタイプの複数のイベント
同じタイプの 2 つのイベントが要素にある場合、イベントのバブルアップを停止すると、イベントの 1 つが発生しなくなる可能性があります。ある種のキャッシュを使用してこれを処理するには、いくつかの方法があります。私の最初の考えは、イベント オブジェクトを変更することでしたが、参照を取得したので、キャッシュ ソリューションで十分であると考えています。