Maison  >  Article  >  interface Web  >  Comment résoudre le clic « cliquez » dans le code fastclick

Comment résoudre le clic « cliquez » dans le code fastclick

亚连
亚连original
2018-06-15 17:39:411432parcourir

Cet article présente principalement le contenu des connaissances pour résoudre complètement le problème du « clic » grâce à l'analyse du code source fastclick. Les amis intéressés peuvent en apprendre davantage.

L'utilisation récente des événements tap m'a posé divers problèmes. L'un des problèmes est que pour résoudre le problème des clics, vous devez changer les clics d'origine en taps. Dans ce cas, nous abandonnerons IE. utilisateurs

Bien sûr, la compatibilité peut être effectuée, mais personne ne veut toucher à l'ancien code, alors aujourd'hui, nous avons proposé le truc fastclick

C'est la quatrième fois que nous publions sur les tap. incident de clic récemment. Nous avons travaillé dur pour le résoudre. J'étais inquiet à propos du masque "clic", alors aujourd'hui, mon patron a proposé une bibliothèque fastclick, qui s'est finalement avérée résoudre notre problème

et cliquez. n'avait pas besoin d'être remplacé par tap, alors notre patron m'a dit sérieusement S'il vous plaît, ne vous méprenez pas, j'ai envoyé tous les e-mails...

Donc, je regardais la bibliothèque fastclick dans l'après-midi. pour voir si cela pouvait résoudre notre problème, nous avons donc commencé

Lisez le code source de fastclick

C'est si simple à utiliser, dites simplement :

FastClick.attach(document.body);

Ainsi, toutes les vitesses de réponse aux clics sont directement améliorées. Le problème de savoir quelle entrée obtient le focus est également résolu ! ! ! Bon sang, si c'est vraiment possible, le collègue qui a changé de page va certainement me donner du fil à retordre

Pas à pas, nous suivrons, l'entrée est la méthode d'attachement :

FastClick.attach = function(layer) {
'use strict';
return new FastClick(layer);
};

Ce frère n'est qu'un exemple. Le code a été modifié, nous devons donc encore regarder notre constructeur :

function FastClick(layer) {
'use strict';
var oldOnClick, self = this;
  this.trackingClick = false;
  this.trackingClickStart = 0;
  this.targetElement = null;
  this.touchStartX = 0;
  this.touchStartY = 0;
  this.lastTouchIdentifier = 0;
  this.touchBoundary = 10;
  this.layer = layer;
  if (!layer || !layer.nodeType) {
   throw new TypeError('Layer must be a document node');
  }
  this.onClick = function() { return FastClick.prototype.onClick.apply(self, arguments); };
  this.onMouse = function() { return FastClick.prototype.onMouse.apply(self, arguments); };
  this.onTouchStart = function() { return FastClick.prototype.onTouchStart.apply(self, arguments); };
  this.onTouchMove = function() { return FastClick.prototype.onTouchMove.apply(self, arguments); };
  this.onTouchEnd = function() { return FastClick.prototype.onTouchEnd.apply(self, arguments); };
  this.onTouchCancel = function() { return FastClick.prototype.onTouchCancel.apply(self, arguments); };
  if (FastClick.notNeeded(layer)) {
   return;
  }
  if (this.deviceIsAndroid) {
   layer.addEventListener('mouseover', this.onMouse, true);
   layer.addEventListener('mousedown', this.onMouse, true);
   layer.addEventListener('mouseup', this.onMouse, true);
  }
  layer.addEventListener('click', this.onClick, true);
  layer.addEventListener('touchstart', this.onTouchStart, false);
  layer.addEventListener('touchmove', this.onTouchMove, false);
  layer.addEventListener('touchend', this.onTouchEnd, false);
  layer.addEventListener('touchcancel', this.onTouchCancel, false);
 
  if (!Event.prototype.stopImmediatePropagation) {
   layer.removeEventListener = function(type, callback, capture) {
    var rmv = Node.prototype.removeEventListener;
    if (type === 'click') {
     rmv.call(layer, type, callback.hijacked || callback, capture);
    } else {
     rmv.call(layer, type, callback, capture);
    }
   };
 
   layer.addEventListener = function(type, callback, capture) {
    var adv = Node.prototype.addEventListener;
    if (type === 'click') {
     adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
      if (!event.propagationStopped) {
       callback(event);
      }
     }), capture);
    } else {
     adv.call(layer, type, callback, capture);
    }
   };
  }
  if (typeof layer.onclick === 'function') {
   oldOnClick = layer.onclick;
   layer.addEventListener('click', function(event) {
 oldOnClick(event);
 }, false);
 layer.onclick = null;
}
}

Regardez ce code, je ne sais pas ce que font la plupart des attributs ci-dessus. ... donc je l'ai ignoré.

if (!layer || !layer.nodeType) {
throw new TypeError('Layer must be a document node');
}

Il convient de noter ici que nous devons transmettre un nœud au constructeur, sinon des problèmes surviendront

Ensuite, ce type enregistre une souris de base. événements sur ses propres méthodes d'attribut Eh bien, nous parlerons des détails plus tard

Il y a une méthode notNeeded à l'arrière :

 FastClick.notNeeded = function(layer) {
  'use strict';
  var metaViewport;
  if (typeof window.ontouchstart === 'undefined') {
   return true;
  }
  if ((/Chrome\/[0-9]+/).test(navigator.userAgent)) {
   if (FastClick.prototype.deviceIsAndroid) {
    metaViewport = document.querySelector('meta[name=viewport]');
    if (metaViewport && metaViewport.content.indexOf('user-scalable=no') !== -1) {
     return true;
    }
   } else {
    return true;
   }
  }
  if (layer.style.msTouchAction === 'none') {
   return true;
  }
  return false;
 };

Cette méthode est utilisée pour déterminer si un clic rapide est nécessaire. . Le commentaire ne veut pas dire grand chose. Compris, jetons un œil au code

Première phrase :

if (typeof window.ontouchstart === 'undefined') {
 return true;
}

Si l'événement touchstart n'est pas pris en charge, retournez true
PS : Mon sentiment actuel est que fastclick devrait également être un événement tactile simulé, mais il n'y a pas de problème de pointage

Plus tard, j'ai également déterminé quelques problèmes avec Android, je n'y prêterai pas attention ici. il doit prendre en charge le toucher, je suis donc revenu au code principal

Dans le code principal, on voit que si le navigateur ne prend pas en charge les événements tactiles ou a d'autres problèmes,

apparaîtra directement. Ensuite, il y a un attribut deviceIsAndroid. Jetons un coup d'œil (en fait, vous n'avez pas besoin de le regarder pour savoir qu'il s'agit d'un jugement)

FastClick. prototype.deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0;

Événement de liaison

D'accord, ceci Le gars a commencé à lier et à enregistrer des événements, mais rien d'étrange n'a été vu jusqu'à présent

 if (this.deviceIsAndroid) {
  layer.addEventListener('mouseover', this.onMouse, true);
  layer.addEventListener('mousedown', this.onMouse, true);
  layer.addEventListener('mouseup', this.onMouse, true);
 }
 layer.addEventListener('click', this.onClick, true);
 layer.addEventListener('touchstart', this.onTouchStart, false);
 layer.addEventListener('touchmove', this.onTouchMove, false);
 layer.addEventListener('touchend', this.onTouchEnd, false);
 layer.addEventListener('touchcancel', this.onTouchCancel, false);

La fonction d'événement spécifique a été réécrite à l'avant, nous allons donc l'ignorer pour l'instant et continuer à la regarder plus tard (d'ailleurs, ce type a égalisé Il y a suffisamment d'événements spécifiés)

stopImmediatePropagation

Il y a un attribut supplémentaire :

Empêcher le comportement de bouillonnement de l'événement en cours et empêcher tous les mêmes types sur l'élément où se trouve l'événement en cours. la fonction de gestionnaire d'événements de l'événement continue de s'exécuter.

Si un élément a plusieurs fonctions d'écoute d'événements pour le même type d'événement, lorsqu'un événement de ce type est déclenché, les multiples fonctions d'écoute d'événements seront exécutées dans l'ordre. une fonction d'écoute exécute la méthode event.stopImmediatePropagation(), en plus du comportement bouillonnant de l'événement bloqué (rôle de la méthode event.stopPropagation), l'exécution d'autres fonctions d'écoute du même type d'événements liés à l'élément sera également bloqué.

 <html>
     <head>
         <style>
             p { height: 30px; width: 150px; background-color: #ccf; }
             p {height: 30px; width: 150px; background-color: #cfc; }
         </style>
     </head>
     <body>
         <p>
             <p>paragraph</p>
         </p>
         <script>
             document.querySelector("p").addEventListener("click", function(event)
             {
                 alert("我是p元素上被绑定的第一个监听函数");
             }, false);
             document.querySelector("p").addEventListener("click", function(event)
             {
                 alert("我是p元素上被绑定的第二个监听函数");
                 event.stopImmediatePropagation();
                 //执行stopImmediatePropagation方法,阻止click事件冒泡,并且阻止p元素上绑定的其他click事件的事件监听函数的执行.
             }, false);
             document.querySelector("p").addEventListener("click", function(event)
             {
                 alert("我是p元素上被绑定的第三个监听函数");
                 //该监听函数排在上个函数后面,该函数不会被执行.
             }, false);
             document.querySelector("p").addEventListener("click", function(event)
             {
                 alert("我是p元素,我是p元素的上层元素");
                 //p元素的click事件没有向上冒泡,该函数不会被执行.
             }, false);
         </script>
     </body>
 </html>
 if (!Event.prototype.stopImmediatePropagation) {
  layer.removeEventListener = function(type, callback, capture) {
   var rmv = Node.prototype.removeEventListener;
   if (type === &#39;click&#39;) {
    rmv.call(layer, type, callback.hijacked || callback, capture);
   } else {
    rmv.call(layer, type, callback, capture);
   }
  };
 
  layer.addEventListener = function(type, callback, capture) {
   var adv = Node.prototype.addEventListener;
   if (type === &#39;click&#39;) {
    adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
     if (!event.propagationStopped) {
      callback(event);
     }
    }), capture);
   } else {
    adv.call(layer, type, callback, capture);
   }
  };
 }

Ensuite, ce type a redéfini la méthode d'inscription et d'annulation des événements

Regardons d'abord l'événement d'inscription, qui utilise celui de Node. addEventListener. Qu'est-ce que Node ?

De ce point de vue, Node est une propriété système, représentant notre nœud, donc l'événement de déconnexion est réécrit ici

Ici, on constate qu'en fait, il se spécialise uniquement dans le traitement des clics

adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
if (!event.propagationStopped) {
 callback(event);
}
}), capture);

Il y a un pirate de l'air détourné. Je ne sais pas pour le moment, je suppose qu'il a été réécrit au milieu.
Ensuite, je l'ai réécrit ici, je suppose que le détournement est un La méthode existe pour. empêcher plusieurs événements d'être enregistrés sur un dom et exécutés plusieurs fois

Nous ne nous soucions pas de la déconnexion et de l'enregistrement à ce stade, nous avons en fait réécrit l'enregistrement que nous avons transmis dans le dom. a été déconnecté. Cela semble très puissant. Cela signifie que le DOM utilisera le nôtre pour appeler l'événement click à l'avenir. Bien sûr, ce n'est que mon jugement temporaire, je dois en savoir plus pour plus de détails. le jugement n'est pas fiable, alors continuons

Lorsque nous nous déconnectons de l'événement, nous pouvons utiliser addEventListener ou dom.onclick=function(){}, voici donc le code suivant :

if (typeof layer.onclick === &#39;function&#39;) {
 oldOnClick = layer.onclick;
 layer.addEventListener(&#39;click&#39;, function(event) {
 oldOnClick(event);
 }, false);
 layer.onclick = null;
}

Ici, son processus principal est en fait terminé, ce qui signifie que toute sa logique est là. Que l'entrée ou la sortie soit l'inscription à l'événement, écrivons donc un code pour voir

Test d'entrée

 <input type="button" value="addevent">
 <input type="button" value="addevent1">
 $(&#39;#addEvent&#39;).click(function () {
     var dom = $(&#39;#addEvent1&#39;)[0]
     dom.addEventListener(&#39;click&#39;, function () {
         alert(&#39;&#39;)
         var s = &#39;&#39;;
     })
 });
Venons-en à ce point d'arrêt pour voir ce que nous avons fait après avoir cliqué. Maintenant que nous cliquons sur le bouton 1, un événement sera enregistré pour le bouton 2 :

.

但是很遗憾,我们在电脑上不能测试,所以增加了我们读代码的困难,在手机上测试后,发现按钮2响应很快,但是这里有点看不出问题

最后alert了一个!Event.prototype.stopImmediatePropagation发现手机和电脑都是false,所以我们上面搞的东西暂时无用

 FastClick.prototype.onClick = function (event) {
     &#39;use strict&#39;;
     var permitted;
     alert(&#39;终于尼玛进来了&#39;);
     if (this.trackingClick) {
         this.targetElement = null;
         this.trackingClick = false;
         return true;
     }
     if (event.target.type === &#39;submit&#39; && event.detail === 0) {
         return true;
     }
     permitted = this.onMouse(event);
     if (!permitted) {
         this.targetElement = null;
     }
     return permitted;
 };

然后我们终于进来了,现在我们需要知道什么是trackingClick 了

/**
* Whether a click is currently being tracked.
* @type Boolean
*/
this.trackingClick = false;

我们最初这个属性是false,但是到这里就设置为true了,就直接退出了,说明绑定事件终止,算了这个我们暂时不关注,我们干点其它的,

因为,我觉得重点还是应该在touch事件上

PS:到这里,我们发现这个库应该不只是将click加快,而是所有的响应都加快了

我在各个事件部分log出来东西,发现有click的地方都只执行了touchstart与touchend,于是至此,我觉得我的观点成立
他使用touch事件模拟量click,于是我们就只跟进这一块就好:

 FastClick.prototype.onTouchStart = function (event) {
     &#39;use strict&#39;;
     var targetElement, touch, selection;
     log(&#39;touchstart&#39;);
     if (event.targetTouches.length > 1) {
         return true;
     }
     targetElement = this.getTargetElementFromEventTarget(event.target);
     touch = event.targetTouches[0];
     if (this.deviceIsIOS) {
         selection = window.getSelection();
         if (selection.rangeCount && !selection.isCollapsed) {
             return true;
         }
         if (!this.deviceIsIOS4) {
             if (touch.identifier === this.lastTouchIdentifier) {
                 event.preventDefault();
                 return false;
             }
             this.lastTouchIdentifier = touch.identifier;
             this.updateScrollParent(targetElement);
         }
     }
     this.trackingClick = true;
     this.trackingClickStart = event.timeStamp;
     this.targetElement = targetElement;
     this.touchStartX = touch.pageX;
     this.touchStartY = touch.pageY;
     if ((event.timeStamp - this.lastClickTime) < 200) {
         event.preventDefault();
     }
     return true;
 };

其中用到了一个方法:

FastClick.prototype.getTargetElementFromEventTarget = function (eventTarget) {
  &#39;use strict&#39;;
  if (eventTarget.nodeType === Node.TEXT_NODE) {
    return eventTarget.parentNode;
  }
  return eventTarget;
};

他是获取我们当前touchstart的元素

然后将鼠标的信息记录了下来,他记录鼠标信息主要在后面touchend时候根据x、y判断是否为click
是ios情况下还搞了一些事情,我这里跳过去了

然后这里记录了一些事情就跳出去了,没有特别的事情,现在我们进入我们的出口touchend

 FastClick.prototype.onTouchEnd = function (event) {
     &#39;use strict&#39;;
     var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
     log(&#39;touchend&#39;);
     if (!this.trackingClick) {
         return true;
     }
     if ((event.timeStamp - this.lastClickTime) < 200) {
         this.cancelNextClick = true;
         return true;
     }
     this.lastClickTime = event.timeStamp;
     trackingClickStart = this.trackingClickStart;
     this.trackingClick = false;
     this.trackingClickStart = 0;
     if (this.deviceIsIOSWithBadTarget) {
         touch = event.changedTouches[0];
         targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;
         targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
     }
     targetTagName = targetElement.tagName.toLowerCase();
     if (targetTagName === &#39;label&#39;) {
         forElement = this.findControl(targetElement);
         if (forElement) {
             this.focus(targetElement);
             if (this.deviceIsAndroid) {
                 return false;
             }
             targetElement = forElement;
         }
     } else if (this.needsFocus(targetElement)) {
         if ((event.timeStamp - trackingClickStart) > 100 || (this.deviceIsIOS && window.top !== window && targetTagName === &#39;input&#39;)) {
             this.targetElement = null;
             return false;
         }
         this.focus(targetElement);
         if (!this.deviceIsIOS4 || targetTagName !== &#39;select&#39;) {
             this.targetElement = null;
             event.preventDefault();
         }
         return false;
     }
     if (this.deviceIsIOS && !this.deviceIsIOS4) {
         scrollParent = targetElement.fastClickScrollParent;
         if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
             return true;
         }
     }
     if (!this.needsClick(targetElement)) {
         event.preventDefault();
         this.sendClick(targetElement, event);
     }
     return false;
 };

这个家伙洋洋洒洒干了许多事情

这里纠正一个错误,他onclick那些东西现在也执行了......可能是我屏幕有变化(滑动)导致

if ((event.timeStamp - this.lastClickTime) < 200) {
 this.cancelNextClick = true;
 return true;
}

这个代码很关键,我们首次点击会执行下面的逻辑,如果连续点击就直接完蛋,下面的逻辑丫的不执行了......
这个不执行了,那么这个劳什子又干了什么事情呢?
事实上下面就没逻辑了,意思是如果确实点击过快,两次点击只会执行一次,这个阀值为200ms,这个暂时看来是没有问题的

好了,我们继续往下走,于是我意识到又到了一个关键点
因为我们用tap事件不能使input获得焦点,但是fastclick却能获得焦点,这里也许是一个关键,我们来看看几个与获取焦点有关的函数

 FastClick.prototype.focus = function (targetElement) {
     &#39;use strict&#39;;
     var length;
     if (this.deviceIsIOS && targetElement.setSelectionRange) {
         length = targetElement.value.length;
         targetElement.setSelectionRange(length, length);
     } else {
         targetElement.focus();
     }
 };

setSelectionRange是我们的关键,也许他是这样获取焦点的......具体我还要下来测试,留待下次处理吧
然后下面如果时间间隔过长,代码就不认为操作的是同一dom结构了

最后迎来了本次的关键:sendClick,无论是touchend还是onMouse都会汇聚到这里

 FastClick.prototype.sendClick = function (targetElement, event) {
     &#39;use strict&#39;;
     var clickEvent, touch;
     // On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
     if (document.activeElement && document.activeElement !== targetElement) {
         document.activeElement.blur();
     }
     touch = event.changedTouches[0];
     // Synthesise a click event, with an extra attribute so it can be tracked
     clickEvent = document.createEvent(&#39;MouseEvents&#39;);
     clickEvent.initMouseEvent(&#39;click&#39;, true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
     clickEvent.forwardedTouchEvent = true;
     targetElement.dispatchEvent(clickEvent);
 };

他创建了一个鼠标事件,然后dispatchEvent事件(这个与fireEvent类似)

 //document上绑定自定义事件ondataavailable
 document.addEventListener(&#39;ondataavailable&#39;, function (event) {
 alert(event.eventType);
 }, false);
 var obj = document.getElementById("obj");
 //obj元素上绑定click事件
 obj.addEventListener(&#39;click&#39;, function (event) {
 alert(event.eventType);
 }, false);
 //调用document对象的 createEvent 方法得到一个event的对象实例。
 var event = document.createEvent(&#39;HTMLEvents&#39;);
 // initEvent接受3个参数:
 // 事件类型,是否冒泡,是否阻止浏览器的默认行为
 event.initEvent("ondataavailable", true, true);
 event.eventType = &#39;message&#39;;
 //触发document上绑定的自定义事件ondataavailable
 document.dispatchEvent(event);
 var event1 = document.createEvent(&#39;HTMLEvents&#39;);
 event1.initEvent("click", true, true);
 event1.eventType = &#39;message&#39;;
 //触发obj元素上绑定click事件
 document.getElementById("test").onclick = function () {
 obj.dispatchEvent(event1);
 };

至此,我们就知道了,我们为dom先绑定了鼠标事件,然后touchend时候触发了,而至于为什么本身注册的click未触发就要回到上面代码了

解决“点透”(成果)

有了这个思路,我们来试试我们抽象出来的代码:

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
     <title></title>
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
     <style>
         #list { display: block; position: absolute; top: 100px; left: 10px; width: 200px; height: 100px; }
         p { display: block; border: 1px solid black; height: 300px; width: 100%; }
         #input { width: 80px; height: 200px; display: block; }
     </style>
 </head>
 <body>
     <p>
     </p>
     <p>
         <p>
             <input type="text" />
         </p>
     </p>
     <script type="text/javascript">
         var el = null;
         function getEvent(el, e, type) {
             e = e.changedTouches[0];
             var event = document.createEvent(&#39;MouseEvents&#39;);
             event.initMouseEvent(type, true, true, window, 1, e.screenX, e.screenY, e.clientX, e.clientY, false, false, false, false, 0, null);
             event.forwardedTouchEvent = true;
             return event;
         }
         list.addEventListener(&#39;touchstart&#39;, function (e) {
             var firstTouch = e.touches[0]
             el = firstTouch.target;
             t1 = e.timeStamp;
         })
         list.addEventListener(&#39;touchend&#39;, function (e) {
             e.preventDefault();
             var event = getEvent(el, e, &#39;click&#39;);
             el.dispatchEvent(event);
         })
         var list = document.getElementById(&#39;list&#39;);
         list.addEventListener(&#39;click&#39;, function (e) {
             list.style.display = &#39;none&#39;;
             setTimeout(function () {
                 list.style.display = &#39;&#39;;
             }, 1000);
         })
     </script>
 </body>
 </html>

这样的话,便不会点透了,这是因为zepto touch事件全部绑定值document,所以 e.preventDefault();无用
结果我们这里是直接在dom上,e.preventDefault();
便起了作用不会触发浏览器默认事件,所以也不存在点透问题了,至此点透事件告一段落......

帮助理解的图

代码在公司写的,回家后不知道图上哪里了,各位将就看吧

为什么zepto会点透/fastclick如何解决点透

我最开始就给老大说zepto处理tap事件不够好,搞了很多事情出来

因为他事件是绑定到document上,先touchstart然后touchend,根据touchstart的event参数判断该dom是否注册了tap事件,有就触发

于是问题来了,zepto的touchend这里有个event参数,我们event.preventDefault(),这里本来都是最上层了,这就代码压根没什么用

但是fastclick处理办法不可谓不巧妙,这个库直接在touchend的时候就触发了dom上的click事件而替换了本来的触发时间

意思是原来要350-400ms执行的代码突然就移到了50-100ms,然后这里虽然使用了touch事件但是touch事件是绑定到了具体dom而不是document上

Donc e.preventDefault est efficace. Nous pouvons empêcher les bulles et les événements par défaut du navigateur. C'est l'essence même de fastclick, ce qui n'est pas mal ! ! !

Lire l'intégralité du code fastclick est incroyable, j'ai beaucoup gagné aujourd'hui, je vais l'enregistrer ici

Postscript

Il y a quelque chose qui ne va pas avec la déclaration ci-dessus, veuillez corriger it :

Tout d'abord, revenons à la solution zepto originale et voyons quels problèmes elle présente :

Comme le standard js ne prend pas en charge les événements tap, zepto tap est simulé par touchstart et touchend. Zepto donne le document lorsqu'il est initialisé. Lier l'événement tactile, obtenir l'élément actuel en fonction du paramètre de l'événement lorsque nous cliquons et enregistrer la position de la souris lorsque nous cliquons et quittons. Déterminez s'il s'agit d'un événement de type clic en fonction du. plage de mouvement de la souris de l'élément actuel. Si c'est le cas, déclenchez l'événement tap enregistré

Ensuite, le traitement du fastclick est fondamentalement le même que celui de zepto, mais différent

fastclick lie l'événement à l'élément que vous transmettez. (généralement document.body)

② Après touchstart et touchend (le click el actuel sera obtenu manuellement), s'il s'agit d'un événement click, l'événement click de l'élément dom sera déclenché manuellement

, donc l'événement de clic sera déclenché au toucher et la vitesse de réponse totale augmentera, le déclencheur est en fait le même que zepto tap

D'accord, pourquoi est-ce avec fondamentalement le même code, zepto. peut cliquer mais fastclick ne peut pas ?

La raison est qu'il y a un settimeout dans le code de zepto, et même exécuter e.preventDefault() dans ce code ne sera pas utile

C'est la différence fondamentale, car settimeout donnera la priorité au supérieur Faible

Avec le timer, lorsque le code est exécuté pour setTimeout, ce code sera placé à la fin du moteur JS

et notre code détectera immédiatement e.preventDefault, Une fois settimeout est ajouté, e.preventDefault ne prendra pas effet. C'est la cause première du point de zepto.

Conclusion

Ce qui précède est ce que j'ai compilé pour tout le monde, j'espère qu'il sera utile à tout le monde. à l'avenir.

Articles associés :

Utiliser le recadrage gm pour synthétiser des images sous Nodejs

Comment appeler json en utilisant js

Comment implémenter le robot d'indexation Baidu à l'aide de la technologie de reconnaissance d'image Puppeteer

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn