js原生實(shí)現(xiàn)FastClick事件的實(shí)例
注明:本人學(xué)習(xí)javascript時(shí)間不長(zhǎng),最近一直在做web端的手機(jī)網(wǎng)頁和微信應(yīng)用,由于最近有用到類似fastclick的功能,在原來的程序中用touchstart和touchend事件模擬,現(xiàn)在嘗試將其封裝,得到了以下兩種有問題的方案。分享給大家,另求大神指導(dǎo)
在手機(jī)端Web app開發(fā)中,click事件的300ms的延遲,會(huì)造成響應(yīng)緩慢,尤其在低端機(jī)中尤為明顯。而使用touchstart或者touchend事件,會(huì)和默認(rèn)的滾輪事件發(fā)生沖突,這也不是我們所期望的。
所以,自己動(dòng)手,豐衣足食,寫了一個(gè)快速點(diǎn)擊事件的原生js代碼(考慮到web app開發(fā)的環(huán)境,我們暫時(shí)無需考慮對(duì)IE等瀏覽器的兼容)。
實(shí)現(xiàn)方法1如下:
function FastClickEvent(handler){ var fastclick = { handler : handler, bind : function(query){ var targetList = document.querySelectorAll(query); for(var i=0,len=targetList.length;i<len;i++) { targetList[i].addEventListener('touchstart',handleEvent); targetList[i].addEventListener('touchend',handleEvent); } }, unbind : function(query){ var targetList = document.querySelectorAll(query); for(var i=0,len=targetList.length;i<len;i++) { targetList[i].removeEventListener('touchstart',handleEvent); targetList[i].removeEventListener('touchend',handleEvent); } } } var touchX = 0 ,touchY = 0; function handleEvent(event){ switch(event.type) { case 'touchstart': touchX = event.touches[0].clientX; touchY = event.touches[0].clientY; break; case 'touchend': var x = event.changedTouches[0].clientX; var y = event.changedTouches[0].clientY; if(Math.abs(touchX-x)<5||Math.abs(touchY-y)<5) fastclick.handler(event); break; } }; return fastclick; };
原理:根據(jù)連續(xù)touchstart和touchend事件發(fā)生時(shí)位置的變化,來判斷是否是一次點(diǎn)擊
調(diào)用:用一個(gè)handler函數(shù)來注冊(cè)一個(gè)FastClickEvent事件。然后將注冊(cè)好的FastClickEvent事件,通過bind方法,綁定到對(duì)應(yīng)的元素上去。如下:
var handler = function(event){ console.log(event.target.id+" fastclicked"); } var fastClick = new FastClickEvent(handler); fastClick.bind("div");
這段代碼,我們給所有的div元素注冊(cè)了fastclick的handler事件。調(diào)用fastClick.unbind來解除元素的綁定。
但是這段代碼有一個(gè)問題,為了讓handleEvent事件能夠訪問到touchX,touchY。我采用了閉包的手法,這意味著每次new一個(gè)FastClickEvent事件對(duì)象,都要在內(nèi)存中再次注入重復(fù)的handleEvent函數(shù)。至于重復(fù)的touchX,touchY,更是不必多說了。
新手求助:原本是想把handleEvent函數(shù)寫到原型里,但是產(chǎn)生的一個(gè)問題是handleEvent(event)的this對(duì)象是windows,也就是說,我取不到touchX和touchY以及handler對(duì)象,造成訪問錯(cuò)誤。
有一種比較簡(jiǎn)單的解決思路,就是只注冊(cè)一個(gè)fastClickEvent事件,然后在處理程序中根據(jù)event.target的實(shí)際值(即發(fā)生事件的對(duì)象上)來決定響應(yīng)的內(nèi)容。
但是,這意味著你必須對(duì)所有的fastclick事件都非常熟悉。
用這種方法帶來的好處在于,由于你只有一個(gè)handleEvent函數(shù),所以基本來說,在頁面釋放之前,除非是你不想再觸發(fā)fastclick事件,否則無需去解綁任何元素的fastclick事件(即使你解綁了,內(nèi)存中仍然存在該handler函數(shù))。而且,你可以很方便的用bind(query)來添加任何動(dòng)態(tài)生成的元素的fastclick事件,只要你在handler函數(shù)中已經(jīng)寫好相應(yīng)的處理程序。
如果你想添加多個(gè)fastclick事件,而且可能要在多個(gè)地方注冊(cè),那么也只要new一個(gè)新的FastClickEvent對(duì)象,然后綁定到對(duì)應(yīng)的元素中去就可以了。
下面,介紹一種使用EventTarget類的方法。首先看一下EventTarget
function EventTarget(){ this.handlers = {}; } EventTarget.prototype = { constructor: EventTarget, addHandler : function(type,handler){ if(typeof this.handlers[type] == "undefined"){ this.handlers[type]=[]; } this.handlers[type].push(handler); }, fire : function(event){ if(!event.target){ event.target = this; } if(this.handlers[event.type] instanceof Array){ var handlers = this.handlers[event.type]; for(var i=0,len=handlers.length;i<len;i++){ handlers[i](event); } } }, removeHandler : function(type,handler){ if(this.handlers[type] instanceof Array){ var handlers = this.handlers[type]; for(var i=0,len=handler.length;i<len;i++){ if(handlers[i]==handler){ break; } } handlers.splice(i,1); } } }
這個(gè)類,是一個(gè)用來添加、移除以及實(shí)現(xiàn)自定義類的接口。參考《JavaScript高級(jí)程序設(shè)計(jì)第三版》P616-617
那么,如何把這個(gè)類,變成我們的fastclick事件接口呢?
定義一個(gè)全局變量,用這個(gè)變量來完成所有的fastclick事件注冊(cè)、刪除以及添加
var FastClick = function(){ var fastclick = new EventTarget(), touchX = 0 , touchY = 0; function handleEvent(event){ switch(event.type) { case 'touchstart': touchX = event.touches[0].clientX; touchY = event.touches[0].clientY; break; case 'touchend': var x = event.changedTouches[0].clientX; var y = event.changedTouches[0].clientY; if(Math.abs(touchX-x)<5||Math.abs(touchY-y)<5) fastclick.fire({type:'fastclick',target:event.target}); break; } }; fastclick.bind = function(query) { var targetList = document.querySelectorAll(query); for(var i=0,len=targetList.length;i<len;i++) { targetList[i].addEventListener('touchstart',handleEvent); targetList[i].addEventListener('touchend',handleEvent); } } Fastclick.unbind = function(query){ var targetList = document.querySelectorAll(query); for(var i=0,len=targetList.length;i<len;i++) { targetList[i].removeEventListener('touchstart',handleEvent); targetList[i].removeEventListener('touchend',handleEvent); } } return fastclick; }();
這個(gè)全局變量FastClick可以用來添加任意的fastclick事件。
下面來講講如何調(diào)用。
添加事件函數(shù):
FastClick.addHandler('fastclick',function(event){});
刪除事件函數(shù)://匿名事件無法刪除
FastClick.removeHandler('fastclick',handler);
綁定元素
FastClick.bind("div");
解綁
FastClick.unbind("div");
用這個(gè)方法,同樣需要我們?cè)趆andler事件中對(duì)event.target做預(yù)判,因?yàn)殡m然這種方法可以添加多個(gè)fastclick事件,但是,事件在執(zhí)行的過程中是按順序一個(gè)一個(gè)執(zhí)行的,也就是說,可能會(huì)執(zhí)行你并不想執(zhí)行的函數(shù)。
帶來的好處在于,可以注冊(cè)多個(gè)fastclick事件,而且無需再次綁定,就可以執(zhí)行了。
比如說,
FastClick.bind("div"); FastClick.addHandler(handler1); FastClick.addHandler(handler2);
那么,當(dāng)快速點(diǎn)擊事件發(fā)生在任一div元素時(shí),就會(huì)順序執(zhí)行handler1和handler2。
如果我們調(diào)用removeHandler來刪除handler1或handler2,那么相應(yīng)的函數(shù)就不會(huì)再執(zhí)行了。
另外,需要注意的是,在handler函數(shù)中,this對(duì)象是FastClick.handlers['fastclick']這個(gè)數(shù)組,一般情況下,我們用event.target來獲取發(fā)生事件的對(duì)象。
用這種方法,基本克服了上面方法的問題,而且,對(duì)這個(gè)對(duì)象重復(fù)new并沒有多大的意義,除非你不想對(duì)event.target做預(yù)判,從而生成一大堆的FaskClick類,但這顯然是不高效的。
新手求助:如何能夠?qū)崿F(xiàn)特定的元素的綁定執(zhí)行的函數(shù),也就是: 能夠調(diào)用FastClick.bind(query,handler);實(shí)現(xiàn)對(duì)符合query條件的元素添加handler的fastclick事件。
以上就是小編為大家?guī)淼膉s原生實(shí)現(xiàn)FastClick事件的實(shí)例全部?jī)?nèi)容了,希望大家多多支持腳本之家~
- vue.js添加一些觸摸事件以及安裝fastclick的實(shí)例
- vue.js 添加 fastclick的支持方法
- JavaScript中click和onclick本質(zhì)區(qū)別與用法分析
- JS實(shí)現(xiàn)同一DOM元素上onClick事件與onDblClick事件并存的解決方法
- JS中touchstart事件與click事件沖突的解決方法
- 詳解vue.js的事件處理器v-on:click
- AngularJS的ng-click傳參的方法
- 詳解angularJS動(dòng)態(tài)生成的頁面中ng-click無效解決辦法
- Angularjs為ng-click事件傳遞參數(shù)
- JS基于onclick事件實(shí)現(xiàn)單個(gè)按鈕的編輯與保存功能示例
- JS實(shí)現(xiàn)頁面中所有img對(duì)象添加onclick事件及新窗口查看圖片的方法
- 快速解決js開發(fā)下拉框中blur與click沖突
- Javascript中綁定click事件的四種方式介紹
相關(guān)文章
js+canvas實(shí)現(xiàn)圖片格式webp/png/jpeg在線轉(zhuǎn)換
這篇文章主要介紹了js+canvas實(shí)現(xiàn)圖片格式webp/png/jpeg在線轉(zhuǎn)換,需要的朋友可以參考下2020-08-08JavaScript 函數(shù)節(jié)流詳解及方法總結(jié)
這篇文章主要介紹了JavaScript 函數(shù)節(jié)流詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-02-02關(guān)于TypeScript模塊導(dǎo)入的那些事
Typescrit的模塊機(jī)制與es6的模塊基本類似,也提供了轉(zhuǎn)換為amd,es6,umd,commonjs,system的轉(zhuǎn)換,下面這篇文章就來給大家詳細(xì)介紹了關(guān)于TypeScript模塊導(dǎo)入的那些事,需要的朋友可以參考借鑒,下面來一起看看吧2018-06-06微信小程序云函數(shù)使用mysql數(shù)據(jù)庫過程詳解
這篇文章主要介紹了微信小程序云函數(shù)使用mysql數(shù)據(jù)庫過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08自己實(shí)現(xiàn)string的substring方法 人民幣小寫轉(zhuǎn)大寫,數(shù)字反轉(zhuǎn),正則優(yōu)化
這是最近碰到的幾個(gè)題目,簡(jiǎn)單地寫一下我自己的方案,在此分享給大家,也希望能看到大家的方案2012-09-09選擇指定數(shù)量后checkbox不可選(變灰)javascript代碼
選擇指定數(shù)量后checkbox不可選(變灰)javascript代碼2009-06-06