web-dev-qa-db-fra.com

Alternative préférée à OnMouseOver pour le toucher

Existe-t-il une alternative ou une pratique recommandée pour la gestion des événements javascript OnMouseOver sur des appareils tactiles? Tout ce que je peux penser, c’est de convertir tous les événements en OnMouseClick. Malheureusement, cela brouille les différences entre les événements déclenchés en déplaçant le curseur et les événements déclenchés en cliquant sur le curseur. 

Existe-t-il des solutions de rechange ou des solutions moins perturbatrices pour l’utilisation universelle d’une page Web qui sera utilisée avec des souris et des appareils tactiles?

39
Daniel Nill

Existe-t-il une alternative ou une pratique recommandée pour la gestion des événements javascript OnMouseOver sur des appareils tactiles?

La réponse courte est non.

Les événements spécifiques à un périphérique ne disposent pas d'un mappage 1: 1 avec les événements d'autres périphériques. Il n'y a pas d'équivalent approprié de «survoler» lorsque vous utilisez Touch.

Les événements de souris (mouseover, mouseout, mousedown, mouseup, mousemove, etc.) sont spécifiques au périphérique d'entrée de la souris. Le clavier a keydown, keypress et keyup. Appuyez sur touchstart, touchmove, touchend et touchcancel. Webkit sur l'iPhone/iPad/etc comporte des événements gesture début/déplacement/fin supplémentaires spécifiques à Apple.

Les événements génériques de niveau supérieur tels que focus, blur, click, submit, etc. peuvent être déclenchés par l'un de ces événements. Un événement click, par exemple, peut être déclenché à l'aide d'un événement souris, tactile ou clavier. (click, btw, est un événement avec un nom inapproprié, qui devrait plutôt s'appeler action mais, en raison de son historique de souris, il s'appelle toujours click).

L'approche préférée (ou "One Web") consiste à utiliser les événements Mouse pour des tâches spécifiques à la souris pour lesquelles vous ne pouvez pas les éviter et à vous en tenir aux événements génériques pour tout le reste.

En fonction de la construction WebKit et des indicateurs utilisés, vous pouvez déclencher des événements de souris sur des interfaces tactiles dans des cas particuliers, mais vous ne voulez vraiment pas construire votre interface utilisateur. parce que la seule raison pour laquelle ces cas existent est de permettre à mobile-Webkit de gagner du terrain sur le marché.

Les événements tactiles sont également incohérents d'une plate-forme à l'autre. Jetez un coup d'oeil au travail de ppk pour une référence si vous faites des choses mobiles/tactiles, http://quirksmode.org/mobile/tableTouch.html

34
Michiel Kalkman

Les événements javascript onmouseover/onmouseout se traduiraient en événements touchenter/touchleave touch, le problème est que ces événements commencent tout juste à être mis en œuvre dans les navigateurs (ils font partie d'un W3C draft ), actuellement uniquement firefox , donc si vous utilisez webkit, vous devrez l’attendre ou implémenter votre fonctionnalité onmouseover en utilisant un événement touchmove et en regardant les coordonnées pour voir si elles se chevauchent avec celles de votre élément html.

6
Nelson

En fonction de vos demandes et des utilisateurs ciblés, vous pouvez être intéressé par les API JS tactiles disponibles (au moins) sur Safari et Chrome mobiles. Vérifiez http://backtothecode.blogspot.com/2009/10/javascript-touch-and-gesture-events.html , pour une introduction rapide (peut-être un peu datée). Je ne les ai pas beaucoup utilisées (uniquement pour l'iPhone, par exemple), mais je suis très satisfait des résultats obtenus jusqu'à présent.

3
Gustav Barkefors

Malheureusement, je ne connais pas les meilleures pratiques ou une alternative preferred à onmouseover sur les appareils tactiles, mais en rencontrant la même question, j'ai fini par développer cette solution vanillaJS où je compte les millisecondes entre onmouseenter et onclick faire la distinction entre un clic sur le bureau et un clic sur un mobile.

En examinant les deux événements dans les environnements de bureau et mobile, j'ai découvert qu'un téléphone mobile déclenche automatiquement les deux événements instantanément (tous les deux en moins de millisecondes), contrairement au petit délai de quelques dizaines de millisecondes qui dépend du déclencheur de l'utilisateur. -bonheur.

;(function(){
	let
		hover_on_mobile = {
			timer: 0,
      // I don't trust the timer with this,
      // so I'm counting myself:
			milliseconds: 0,
      // also cover the case of the user
      // mouseentering, reading or otherwise
      // waiting, and clicking *then*.
			is_counting: false,
		},
    item = document.querySelector('.mobile-hoverable')
	;
	hover_on_mobile.reset = function(){
		clearInterval(hover_on_mobile.timer);
		hover_on_mobile.milliseconds = 0;
		hover_on_mobile.is_counting = false;
	};

	// hover.
	item.onmouseenter = function(){

		// preparation for onclick's touch-click detection.
		hover_on_mobile.is_counting = true;
		// count the milliseconds starting on each 
    // mouseenter anew.
		hover_on_mobile.timer = window.setInterval(function() {
			// we only need the first few milliseconds for
      // our touch-click detection.
			if (hover_on_mobile.milliseconds > 50) {
				hover_on_mobile.reset();

			} else {
				hover_on_mobile.milliseconds++;
			}
		}, 1);

		hover_behavior();
	};

	// click.
	item.onclick = function(ev){
		let
			condition1 = hover_on_mobile.milliseconds < 10,
			condition2 = hover_on_mobile.is_counting
		;
		console.log('clicked', {
			condition1: condition1,
			condition2: condition2,
			timer: hover_on_mobile.timer,
      milliseconds: hover_on_mobile.milliseconds,
			is_counting: hover_on_mobile.is_counting,
		});
		// touch-click detection.
		if (condition1 && condition2) {
			// don't do anything; let the onmouseenter 
      // do the hover routine unhinderedly.
      //
			// if this was an onclick event on an ‹a› tag, 
      // the ev.preventDefault(); call would go here.
      
		} else {
			click_behavior();
		}
		hover_on_mobile.reset();
	};
  
  
  // ----------------------------------------
  // fiddle-specfic.

	// reset indicator, not hover_on_mobile.
	item.onmouseout = reset_indicator;

	function click_behavior() {
		document.querySelector('#indicator .click-text').innerText = 'clicked';
	}

	function hover_behavior() {
		document.querySelector('#indicator .hover-text').innerText = 'hovered';
	}

	function reset_indicator() {
		document.querySelector('#indicator .hover-text').innerText = '-';
		document.querySelector('#indicator .click-text').innerText = '-';
	}

	document.querySelector('#indicator .reset').onclick = reset_indicator;

})();
h1 {
  font-size: 20px;
  line-height: 26px;
}

#indicator {
  margin-top: 15px;
  padding: 20px;
  background-color: #ddd;
}

.mobile-hoverable {
  cursor: pointer;
  background-color: antiquewhite;
  border: 1px outset blanchedalmond;
  border-radius: 4px;
  padding: 10px;
}

.notes {
  font-style: italic;
  font-size: 14px;
}
<div class="root">
  <h1>Imagine you wanted mobile users to click once in order to simulate a desktop-hover and twice for a desktop-click</h1>
  
  <div class="mobile-hoverable">Hover me, click me, compare with mobile-touch device mode.</div>
  
  <div id="indicator">
    <button class="reset">Reset</button>
    <span class="hover-text">-</span>
    <span class="click-text">-</span>
  </div>
  
  <ul class="notes">
    <li>Don't forget to reload the page after changing the mode, for optimal testing evaluation.</li>
    <li>Click event console.logs hover_on_mobile object.</li>
    <li>The fiddle's CSS is irrelevant for this feature.</li>
    <li>Relevant JavaScript is bundled together; irrelevant JavaScript at the end.</li>
    <li>Didn't test browser compatibility specifically for this fiddle but the feature works in Chrome, Firefox, Safari, IE10+.</li>
    <li>Subsequent clicks without onmouseout will only fire the click event, in both environments.</li>
  </ul>
</div>

(… Ou alternativement en tant que violon )

Voici un autre violon pour montrer spécifiquement la différence de temps entre les environnements de bureau et mobiles.

1
WoodrowShigeru

Je pense avoir réussi à créer une bonne simulation (du moins pour un gestionnaire d’événements spécifique que je voulais simuler) en combinant le gestionnaire d’événements 'touchmove' et en appelant la méthode elementFromPoint () à l’aide des coordonnées (stockées dans les propriétés clientX/clientY du objet) de l’objet Touch correspondant à l’événement (j’ai utilisé e.touches [0]). 

Pour une réponse plus détaillée, voir ma réponse pour le cas d'utilisation spécifique de cet utilisateur (remplissage des cellules d'un tableau) basée sur une solution à mon propre problème (basculement des états de case à cocher) ici: https://stackoverflow.com/a/ 31711040/1941313 .

Vous pouvez également lire le rapport complet sur la conception du gestionnaire d’événements en écriture, y compris les sources de mes résultats dans le Gist suivant: https://Gist.github.com/VehpuS/6fd5dca2ea8cd0eb0471

(Je les aurais postées dans stackoverflow mais mon représentant est trop bas pour le moment, donc je ne peux fournir que deux liens: P)

J'espère que cela t'aides!