热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

挪動端觸摸、點擊事宜優化(fastclick源碼進修)

挪動端觸摸、點擊事宜優化(fastclick源碼進修)近來在做一些微信挪動端的頁面,在此紀錄關於挪動端觸摸和點擊事宜的進修優化歷程,主要內容繚繞fastclick睜開。fastcl
挪動端觸摸、點擊事宜優化(fastclick源碼進修)

近來在做一些微信挪動端的頁面,在此紀錄關於挪動端觸摸和點擊事宜的進修優化歷程,主要內容繚繞fastclick睜開。
fastclick github

題目劈頭

挪動端瀏覽器平常在用戶點擊屏幕以後會耽誤約莫300ms才觸發click event

——
GOOGLE

手機翻開此鏈接檢察耽誤demo
(如今很多瀏覽器已不存在耽誤題目了,詳見fastclick github,但筆者的手機瀏覽器照樣湧現了三百毫秒耽誤的題目)
截圖以下
《挪動端觸摸、點擊事宜優化(fastclick源碼進修)》

為何會300ms耽誤呢,主假若有一個雙擊縮放功用,瀏覽器須要推斷用戶點擊是不是為雙擊縮放。這個題目不處置懲罰,
1、用戶體驗就會很差,很不流通,尤其是在麋集操縱場景下,比方計算器,不處置懲罰300ms耽誤題目,覺得迴響反映很慢;
2、點擊穿透題目

事宜觸發遞次

在相識fastclick的思緒之前,我們先看一下事宜觸發遞次是怎樣的

  • touchstart
  • touchmove
  • touchend
  • mouseover :當指針裝備挪動到存在監聽器的元素或其子元素的時刻,mouseover事宜就會被觸發。
  • mouseenter:當指針裝備( 通常指鼠標 )在元素上挪動時, mousemove 事宜被觸發。
  • mousedown
  • click

挪動端click有300ms耽誤題目,touch可沒有哦。

fastclick思緒

fastclick的思緒就是應用touch來模仿tap(觸碰),假如認為是一次有用的tap,則在touchend時馬上模仿一個click事宜,分發到事宜源(相當於主動觸發一次click),同時阻撓掉瀏覽器300ms后發作的click。

源碼進修

先看運用示例,很簡單,我們的思緒就一向隨着attach走。

if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}

直接給body綁定fastlick就好了- -。
看源代碼組織(注:以下一切代碼均去掉了一些不影響明白思緒的部份,大部份思緒寫在解釋中)

//組織函數
function FastClick(layer, options)
//推斷是不是須要瀏覽器原生的click事宜(針對一些特別元素比方表單)
FastClick.prototype.needsClick = function(target)
//發送模仿的click event
FastClick.prototype.sendClick = function(targetElement, event)
// touchstart eventhandler
FastClick.prototype.OnTouchStart= function(event)
// touchmove eventhandler
FastClick.prototype.OnTouchMove= function(event)
// touchend eventhandler
FastClick.prototype.OnTouchEnd= function(event)
// 推斷此次tap是不是有用
FastClick.prototype.OnMouse= function(event)
//click handler 捕捉階段監聽
FastClick.prototype.OnClick= function(event)
//燒毀fastlick,移除事宜綁定
FastClick.prototype.destroy = function()
//綁定接口
FastClick.attach = function(layer, options) {
return new FastClick(layer, options);
};

attach現實就執行了組織函數舉行初始化,接下來我們來看組織函數發作了什麼

function FastClick(layer,options){
//一些屬性初始化
//安卓一些老版本瀏覽器不支持bind, poly fill
function bind (method, context) {
return function () {
return method.apply(context, arguments);
};
}
var methods = ['onMouse', 'onClick', 'onTouchStart', 'onTouchMove',
'onTouchEnd', 'onTouchCancel'];
var cOntext= this;
//將一切handler的this綁定到fastclick實例
for (var i = 0, l = methods.length; i context[methods[i]] = bind(context[methods[i]], context);
}
//為當前fast click對象綁定的layer(我們的示例中時document.body)加監聽
layer.addEventListener('click', this.onClick, true);//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);
}

組織函數主假如初始化一些屬性,polyfill,和增加監聽,
下面最先看一下重頭戲,touchstart,touchend是怎樣推斷tap是不是有用、怎樣模仿click事宜、怎樣阻撓300ms后的click
touchstart

FastClick.prototype.OnTouchStart= function (event) {
var targetElement, touch, selection;
// Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
// 假如多觸點多是在縮放,不對targetElement初始化,在此提早停止防止誤模仿發作click
if (event.targetTouches.length > 1) {
return true;
}
//獵取發作事宜源元素(目的階段的元素)
targetElement = this.getTargetElementFromEventTarget(event.target);
touch = event.targetTouches[0]; this.trackingClick = true;//標記最先跟蹤click
this.trackingClickStart = event.timeStamp;//最先跟蹤時候
this.targetElement = targetElement;//事宜源元素
//觸摸坐標,接下來推斷是不是越界用到
this.touchStartX = touch.pageX;
this.touchStartY = touch.pageY;
// Prevent phantom clicks on fast double-tap (issue #36)
if ((event.timeStamp - this.lastClickTime) event.preventDefault();//阻撓以後的click
}
return true;
};

touchstart主假如初始化跟蹤的tap相干的一些屬性,用於以後的推斷‘
接下來touchmove

FastClick.prototype.OnTouchMove= function (event) {
if (!this.trackingClick) {
return true;
}
// If the touch has moved, cancel the click tracking 挪動到了其他元素
if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {//挪動越界了,作廢本次click模仿處置懲罰,走原生流程
this.trackingClick = false;
this.targetElement = null;
}
return true;
};

touchmove比較簡單,主假如兼容滑動tap(swiper)等等,滑動越界則不模仿click
下面是touchend

FastClick.prototype.OnTouchEnd= function (event) {
var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
if (!this.trackingClick) {
return true;
}
// Prevent phantom clicks on fast double-tap (issue #36)
//阻撓疾速雙擊
if ((event.timeStamp - this.lastClickTime) this.cancelNextClick = true;
return true;
}
//超時就不算click了,走原生流程,不阻撓click
if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) {
return true;
}
this.lastClickTime = event.timeStamp;
this.trackingClick = false;
this.trackingClickStart = 0;
// Prevent the actual click from going though - unless the target node is marked as requiring
// real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
if (!this.needsClick(targetElement)) {
event.preventDefault();//阻撓以後的click
this.sendClick(targetElement, event);//發送模仿click
}
return false;
};
//發送模仿的click event
FastClick.prototype.sendClick = function (targetElement, event) {
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];
//模仿click
// Synthesise a click event, with an extra attribute so it can be tracked
clickEvent = document.createEvent('MouseEvents');
clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
clickEvent.forwardedTouchEvent = true;
//向targetElement分發模仿的click
targetElement.dispatchEvent(clickEvent);
};

末了,還會在layer的click捕捉階段監聽

//click handler 捕捉階段監聽
FastClick.prototype.OnClick= function (event) {
var permitted;
// It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
if (this.trackingClick) {//1、出界會置為false,2勝利模仿了一次完成tap並阻撓click也會置為false,3、防止三方庫影響
this.targetElement = null;
this.trackingClick = false;
return true;
}
// Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
if (event.target.type === 'submit' && event.detail === 0) {
return true;
}
permitted = this.onMouse(event);
// Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through.
if (!permitted) {
this.targetElement = null;
}
// If clicks are permitted, return true for the action to go through.
return permitted;
};
// 推斷此次鼠標是不是有用
FastClick.prototype.OnMouse= function (event) {
// If a target element was never set (because a touch event was never fired) allow the event
if (!this.targetElement) {
return true;
}
// 標記fastclick模仿發作的event
if (event.forwardedTouchEvent) {
return true;
}
// Programmatically generated events targeting a specific element should be permitted
if (!event.cancelable) {
return true;
}
// Derive and check the target element to see whether the mouse event needs to be permitted;
// unless explicitly enabled, prevent non-touch click events from triggering actions,
// to prevent ghost/doubleclicks.
// 是不是須要原生的click
if (!this.needsClick(this.targetElement) || this.cancelNextClick) {
// Prevent any user-added listeners declared on FastClick element from being fired.
if (event.stopImmediatePropagation) {
event.stopImmediatePropagation();
} else {
// Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
event.propagatiOnStopped= true;
}
// Cancel the event 阻撓事宜捕捉和冒泡
event.stopPropagation();
event.preventDefault();
return false;
}
// If the mouse event is permitted, return true for the action to go through.
return true;
};

這裏主假如推斷此次click是不是有用(如無效,則阻撓捕捉和冒泡)
至此基礎流程已完畢。
其中有1個注重的點,筆者在chrome(Version 64.0.3282.119 (Official Build) (64-bit))已測試
stopPropagation,stopImmediatePropagation不僅會阻撓冒泡還會阻撓捕捉歷程哦。

末了

引薦瀏覽源碼,源碼中有很多關於focus、差別瀏覽器兼容和特別表單元素的處置懲罰fastclick github。
這裡是筆者帶有中文解釋的代碼中文解釋代碼。
若有馬虎,迎接批評指正。

Reference

MDN
https://juejin.im/entry/55d73…


推荐阅读
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • 本文介绍了DataTables插件的官方网站以及其基本特点和使用方法,包括分页处理、数据过滤、数据排序、数据类型检测、列宽度自动适应、CSS定制样式、隐藏列等功能。同时还介绍了其易用性、可扩展性和灵活性,以及国际化和动态创建表格的功能。此外,还提供了参数初始化和延迟加载的示例代码。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • 本文介绍了互联网思维中的三个段子,涵盖了餐饮行业、淘品牌和创业企业的案例。通过这些案例,探讨了互联网思维的九大分类和十九条法则。其中包括雕爷牛腩餐厅的成功经验,三只松鼠淘品牌的包装策略以及一家创业企业的销售额增长情况。这些案例展示了互联网思维在不同领域的应用和成功之道。 ... [详细]
  • 微信小程序导航跟随的实现方法
    本文介绍了在微信小程序中实现导航跟随的方法。通过设置导航的position属性和绑定滚动事件,可以实现页面向下滚动到导航位置时,导航固定在页面最上方;页面向上滚动到导航位置时,导航恢复到原始位置;点击导航可以平滑跳转到相应位置。代码示例也给出了具体实现方法。 ... [详细]
  • mui框架offcanvas侧滑超出部分隐藏无法滚动如何解决
    web前端|js教程off-canvas,部分,超出web前端-js教程mui框架中off-canvas侧滑的一个缺点就是无法出现滚动条,因为它主要用途是设置类似于qq界面的那种格 ... [详细]
author-avatar
昆哥2502852107
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有