Mobile Click event causes and workarounds for 300ms latency

Source: Internet
Author: User

This goes back to the beginning of 2007. Apple, on the eve of the launch of its first iPhone, encountered a problem-the site was designed for large-screen devices. So Apple's engineers made some promises to tackle the problem of the IPhone's small screen browsing desktop-side site. The most famous of these is the double-click Zoom (double tap to zoom). This is also the main reason for the 300 millisecond delay mentioned above.

When the user taps the screen one time, the browser does not immediately determine whether the user wants to double-click the zoom or click. As a result, IOS Safari waits 300 milliseconds to determine if the user clicked the screen again.

So the 300 millisecond delay was born.

Fastclick is a lightweight library developed by FT Labs specifically to address the 300 millisecond Click Latency issue for mobile browsers. In short, touchend when an event is detected, Fastclick immediately triggers a click event (custom event) of a simulated event through a DOM custom event click , and blocks the browser from the event that is actually triggered after 300 milliseconds click .

Fastclick a very practical solution to the 300 millisecond click Delay issue. The only drawback might be the file size of the script (though it is not big). If you care much about this file size, try filament Group tappy!, or tap.js. Both are fairly lightweight and can tap bypass the 300-millisecond delay by listening instead of click events.

Of course, in the Zepto library function, there is also a touch module, which also contains the tap event, which can be replaced by a tap to bind the click event.

But Zepto's tap event is a bit of a problem. How to solve, please see the next chapter decomposition.

Next, let's take a detailed look at a problem: Fastclick resolve the source parsing of deferred clicks.

Fastclick solve the source parsing of deferred clicks.

First, let's look at the use of Fastclick.

Window.addeventlistener ("Load", function () {    Fastclick.attach (document.body);}, False);

This solves the problem of 300 millisecond click latency.

Source code for Fastclick:

Fastclick.attach = function (layer) {' Use strict '; return new Fastclick (layer);};

In the Fastclick constructor, there is the following code:

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.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 (' Touchend ', this.ontouchend, false); Layer.addeventlistener (' Touchcancel ', This.ontouchcancel, false); 

That is, the Click,touchstart,touchend,touchcancel incident was bound on document.body.

This assumes that our page has a button that binds the Click event.

When the user taps this button, the Touchstart event is triggered first, and then it bubbles into the document.body, and then it executes:

FastClick.prototype.onTouchStart = function (event) {' Use strict '; var targetelement, Touch, Selection;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;};

This callback function mainly does the following things:

Get the element we currently trigger Touchstart, here is the button.

Then the information of the mouse is recorded, the information of the mouse is mainly for the next touchend trigger, according to the resulting x, y determine whether the click.

After that, the Touchend event is triggered and then bubbled up to document.body, executing the following code:

FastClick.prototype.onTouchEnd = function (event) {' Use strict '; var forelement, Trackingclickstart, Targettagname, Scrollparent, touch, targetelement = this.targetelement;if (this.touchhasmoved (event) | | (Event.timestamp-this.trackingclickstart) >) {this.trackingclick = False;this.targetelement = null;} if (!this.trackingclick) {return true;} if ((Event.timestamp-this.lastclicktime) < $) {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);} Targettagname = TargetElement.tagName.toLowerCase (); if (targettagname = = = ' label ') {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 = = = ' input ')) {this.targetelement = Null;return false;} This.focus (targetelement); if (!this.deviceisios4 | | targettagname!== ' SELECT ') {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;};

Note that the above code, Event.preventdefault (), prevents the triggering of the real click event, so the click event above the button does not fire.

Next, we just need to look at the Sendclick method.

FastClick.prototype.sendClick = function (Targetelement, event) {' Use strict '; var clickevent, Touch;if ( Document.activeelement && document.activeelement!== targetelement) {Document.activeElement.blur ();} Touch = Event.changedtouches[0];clickevent = Document.createevent (' mouseevents ');
Clickevent.initmouseevent (' Click ', True, true, window, 1, Touch.screenx, Touch.screeny, Touch.clientx, Touch.clienty, False, False, False, FALSE, 0, null); clickevent.forwardedtouchevent = True;targetelement.dispatchevent (clickevent);};

In this method, a custom Click event is created and then triggered immediately on the button, so the event callback function of the button-bound click executes immediately, so there is no 300ms delay.

The first three parameters of the Initmouseevent method above mean: 1. Event type, 2. Whether to bubble, 3. Whether to block the default behavior of the browser.

The custom click event blocks the browser's default behavior, and the event bubbles, then executes the Document.body Click event Callback function. The code is as follows:

FastClick.prototype.onClick = function (event) {' Use strict '; var permitted;if (This.trackingclick) {this.targetelement = Null;this.trackingclick = False;return true;} if (Event.target.type = = = ' Submit ' && event.detail = = = 0) {return true;} permitted = This.onmouse (event); if (!permitted) {this.targetelement = null;} return permitted;};

Then there is a sentence permitted = This.onmouse (event); So we look at the Onmouse method:

FastClick.prototype.onMouse = function (event) {' Use strict '; if (!this.targetelement) {return true;} if (event.forwardedtouchevent) {return true;} if (!event.cancelable) {return true;} if (!this.needsclick (this.targetelement) | | this.cancelnextclick) {if (event.stopimmediatepropagation) { Event.stopimmediatepropagation ();} else {event.propagationstopped = true;} Event.stoppropagation (); Event.preventdefault (); return false;} return true;};

This method prevents the bubbling of the simulated click event and the default behavior.

This solves the problem of the mobile browser click event Delay of 300ms.

  

  

  

Come on!

Mobile Click event causes and workarounds for 300ms latency

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.