摘要:所以這種情況下是不符合點(diǎn)擊事件的定義的。,關(guān)于移動(dòng)端的點(diǎn)擊事件總結(jié)完了,可能你都沒想到一個(gè)簡(jiǎn)單的點(diǎn)擊事件會(huì)有那么多坑,如果你在工作中可能會(huì)涉及到移動(dòng)端開發(fā)的話,相信這篇文章還是值得你點(diǎn)贊和收藏的,畢竟是踩了那么多坑的經(jīng)驗(yàn)總結(jié)。
看標(biāo)題的時(shí)候你可能會(huì)想,點(diǎn)擊事件有什么好說的,還寫一篇攻略?哈哈,如果你這么想,只能說明你too young to simple.
接觸過移動(dòng)端開發(fā)的同學(xué)可能都會(huì)面臨點(diǎn)擊事件的第一個(gè)問題:click事件的300ms延遲響應(yīng)。不能立即響應(yīng)給體驗(yàn)造成了很大的困擾,因此解決這個(gè)問題就成為了必然。
這個(gè)問題的解決方案就是:zepto.js的tap事件。tap事件可以理解為在移動(dòng)端的click事件,而zepto.js因?yàn)閹缀跬耆珡?fù)制jQuery的api,因此常常被用在h5的開發(fā)上用來取代jquery.
由于模塊化的原因,導(dǎo)致有的同學(xué)下載的zepto.js的模塊并不全,造成了一大堆悲劇,以為zepto.js不支持一些方法,所以,下載的時(shí)候注意一點(diǎn)。
然而事情到這里并沒有結(jié)束,因?yàn)閠ap事件解決了一個(gè)300ms延遲問題,卻帶來了一個(gè)新的重大bug,點(diǎn)擊穿透。
點(diǎn)擊穿透的意思,就是如果一個(gè)絕對(duì)定位或者固定定位元素處于頁(yè)面最頂層,對(duì)這個(gè)元素綁定一個(gè)點(diǎn)擊事件,那么你點(diǎn)擊這個(gè)點(diǎn)對(duì)應(yīng)的下面凡是有點(diǎn)擊事件或者a標(biāo)簽都會(huì)被觸發(fā)執(zhí)行。這里就不貼圖了,自行腦補(bǔ)各種彈窗,這種情況還是非常多的。
為了解決這個(gè)問題,有的人試圖用touchend來搞定。touchend會(huì)在手指離開手機(jī)屏幕時(shí)觸發(fā)一次。沒有300ms延遲,沒有點(diǎn)擊穿透,看上去簡(jiǎn)直就是完美的解決方案??墒?!
先在這里簡(jiǎn)單總結(jié)一個(gè)小知識(shí)點(diǎn)。
移動(dòng)端有touchstart, touchmove, touchend, 以及tap
pc端有mousedown, mousemove, mouseup, click。
他們的關(guān)系和作用幾乎可以對(duì)應(yīng)起來,分別表示按下,滑動(dòng),松開。pc端可以用前面三個(gè)事件實(shí)現(xiàn)拖拽,移動(dòng)端也可以用前面三個(gè)事件實(shí)現(xiàn)的滑動(dòng)。
所以,在pc端不用mouseup來替換click,就是因?yàn)樗谒砷_鼠標(biāo)的時(shí)候就會(huì)觸發(fā),導(dǎo)致如果我在很遠(yuǎn)的區(qū)域滑動(dòng)到目標(biāo)元素,然后松開,這樣的情況也會(huì)觸發(fā)mouseup與touchend事件。所以這種情況下是不符合點(diǎn)擊事件的定義的。而且如果你在某種情況下,對(duì)某一個(gè)事件需要同時(shí)綁定拖拽和點(diǎn)擊,就更加沒辦法解決了。
另外還有一個(gè)很重要的原因?qū)е聇ouchend不能用來替換點(diǎn)擊,是因?yàn)镻C端不支持。老板們常常希望自己的頁(yè)面不僅僅能夠在移動(dòng)端展示,因此還得想其他辦法。
我知道有經(jīng)驗(yàn)的同學(xué)讀這篇文章的時(shí)候,早就在想fastclick.js了。是的,目前來看,這是一個(gè)非常好的解決方案。為了解決300ms延遲的問題,zepto.js給出了tap事件替換的方案,而fastclick.js則是在想辦法讓click事件的延遲消除。因此任然是使用click事件,也就不會(huì)有點(diǎn)擊穿透的問題。
首先想辦法引入fastclick.js
如果你使用原生js開發(fā)則進(jìn)行如下聲明即可。
if ("addEventListener" in document) { document.addEventListener("DOMContentLoaded", function() { FastClick.attach(document.body); }, false); }
如果你想使用jquery
$(function() { FastClick.attach(document.body); });
如果你在使用CommonJS風(fēng)格的框架,比如requirejs
var attachFastClick = require("fastclick"); attachFastClick(document.body);
AMD
var FastClick = require("fastclick"); FastClick.attach(document.body, options);
進(jìn)行對(duì)應(yīng)的聲明之后,你就可以在移動(dòng)端頁(yè)面中放心大膽的使用click事件了。說到這里,就會(huì)有一個(gè)關(guān)于zepto.js與jquery選擇的問題。說起來又可以寫一大篇文章了,簡(jiǎn)單來說就是,實(shí)際開發(fā)中你就會(huì)發(fā)現(xiàn)zepto還是有點(diǎn)不太爽,雖然體積小點(diǎn),既然click延遲的問題已經(jīng)解決了,我還是更偏向于使用jquery.
當(dāng)然,我們要踩的坑并沒有結(jié)束 - -!
最近開發(fā)了一個(gè)小頁(yè)面,財(cái)經(jīng)日歷,在日歷部分,我需要同時(shí)給代表每一天的元素事件實(shí)現(xiàn)獲取當(dāng)天資訊的需求,又要給整個(gè)日歷部分實(shí)現(xiàn)能夠左右滑動(dòng)來選取上一月和下一月的功能。所以我需要同時(shí)對(duì)日歷部分綁定click事件和實(shí)現(xiàn)滑動(dòng)的touchstart,touchmove,touchend事件。
這個(gè)時(shí)候問題出現(xiàn)了。在安卓手機(jī)上,對(duì)同一個(gè)元素,如果我綁定了click事件,然后在綁定touchstart事件,click事件會(huì)處于幾乎失效的狀態(tài)。就算用了fastclick事件也無(wú)法避免這個(gè)問題
錯(cuò)誤演示大概如下
$area.on("click", ".weeknumber", function() { // 點(diǎn)擊每一天獲取當(dāng)天資訊 }) // 實(shí)現(xiàn)左右滑動(dòng) $area.on("touchstart", function() {}) .on("touchmove", function() {}) .on("touchend", function() {})
動(dòng)手能力強(qiáng)的同學(xué)可以去試試這個(gè)坑,這種情況下,fastfclick肯定是沒辦法解決的。怎么辦?
我的第一次嘗試,是在當(dāng)滑動(dòng)距離為0的時(shí)候,運(yùn)行點(diǎn)擊事件里面的內(nèi)容。我們知道在實(shí)現(xiàn)滑動(dòng)[不知道如何實(shí)現(xiàn)的同學(xué),是時(shí)候關(guān)注我的公眾號(hào)了,搜索isreact找到我]的時(shí)候,會(huì)計(jì)算一個(gè)滑動(dòng)距離。
// 實(shí)現(xiàn)滑動(dòng)的大概代碼 // 滑動(dòng)元素translateX的初始值 var iscroll = device_width, // 用來計(jì)算的中間值 istarX = 0, // 手指第一次點(diǎn)在屏幕上的x坐標(biāo) istart_pageX = 0; // 綁定事件 $area.on("touchstart", touchstart) .on("touchmove", touchmove) .on("touchend", touchend); function touchstart(event) { event.preventDefault(); istartX = iscroll; istart_pageX = event.originalEvent.changedTouches[0].pageX; } function touchmove(event) { // 滑動(dòng)過程中手指位置x坐標(biāo)會(huì)不停變動(dòng),這里會(huì)保存一個(gè)當(dāng)前位置與初始位置的一個(gè)差值 var distance = event.originalEvent.changedTouches[0].pageX - istart_pageX; iscroll = istartX + distance; // 這里是我自定義的一個(gè)css方法,用來設(shè)置元素translateX的當(dāng)前值 Utils.css(area, { translateX: iscroll }); } function touchend(event) { var distance = event.originalEvent.changedTouches[0].pageX - istart_pageX; $area.off("touchstart touchmove touchend"); // 根據(jù)差值的不同,執(zhí)行不同的動(dòng)作 if (distance < -80) { slideNext(function() { addEventSlider($area); }) } else if (distance > 80) { slidePrev(function() { addEventSlider($area); }) } else if (distance == 0) { /* 當(dāng)差值為0時(shí),我認(rèn)為這是執(zhí)行了一次點(diǎn)擊 */ addEventSlider($area); } else { ani(area).animate(400, "easeout", { x: -device_width }, function() { iscroll = -device_width; addEventSlider($area); }) } }
上面就是我的滑動(dòng)功能的實(shí)現(xiàn),中間會(huì)有一些自定義的方法,因此沒辦法你們直接就復(fù)制過去運(yùn)行。但是原理已經(jīng)講得還算明白,可以自己嘗試一些簡(jiǎn)單的實(shí)現(xiàn)。關(guān)注我公眾號(hào)會(huì)有更加詳細(xì)的講解哦!
我的這一次嘗試,就是在滑動(dòng)差值distance為0的時(shí)候,認(rèn)為這是一次點(diǎn)擊,因此執(zhí)行點(diǎn)擊事件應(yīng)該有的動(dòng)作。本來我以為這就能夠解決了,測(cè)試的時(shí)候也通過了。但是 - -!產(chǎn)品同學(xué)非常有執(zhí)念的在日歷上點(diǎn)擊了50多下,結(jié)果發(fā)現(xiàn),多次點(diǎn)擊之后,在點(diǎn)就失去效果了!??!
當(dāng)發(fā)現(xiàn)這個(gè)bug的時(shí)候,我的內(nèi)心是崩潰的。好吧,只能說,試圖用touchend來代替點(diǎn)擊事件的想法終究還是有一點(diǎn)不成熟。硬著頭皮想辦法繼續(xù)解決上面的問題。再三思考各種解決方案,最終決定自己封裝一個(gè)tap事件。封裝的tap事件的代碼如下。
http://yangbo5207.github.io/s...
這是對(duì)jquery事件的一個(gè)拓展,讓jquery也能夠使用tap事件。放在jquery后面引入就能夠立即使用了。除此之外還擴(kuò)展了longTap,swipe兩個(gè)事件。
使用方式和其他一樣。
$area.on("tap", function() {}); $area.tap(function() {})
當(dāng)然我封裝的這個(gè)tap,任然有避免不了的點(diǎn)擊穿透bug,所以,最終的解決方案是:對(duì)于需要同時(shí)綁定點(diǎn)擊事件和滑動(dòng)事件的元素,用tap事件,其他情況都用click事件即可。需要結(jié)合我的tap.js與fastclick.js來完美解決這個(gè)問題。心累啊,終于是搞定了。
OK,關(guān)于移動(dòng)端的點(diǎn)擊事件總結(jié)完了,可能你都沒想到一個(gè)簡(jiǎn)單的點(diǎn)擊事件會(huì)有那么多坑,如果你在工作中可能會(huì)涉及到移動(dòng)端開發(fā)的話,相信這篇文章還是值得你點(diǎn)贊和收藏的,畢竟是踩了那么多坑的經(jīng)驗(yàn)總結(jié)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/49893.html
摘要:所以這種情況下是不符合點(diǎn)擊事件的定義的。,關(guān)于移動(dòng)端的點(diǎn)擊事件總結(jié)完了,可能你都沒想到一個(gè)簡(jiǎn)單的點(diǎn)擊事件會(huì)有那么多坑,如果你在工作中可能會(huì)涉及到移動(dòng)端開發(fā)的話,相信這篇文章還是值得你點(diǎn)贊和收藏的,畢竟是踩了那么多坑的經(jīng)驗(yàn)總結(jié)。 看標(biāo)題的時(shí)候你可能會(huì)想,點(diǎn)擊事件有什么好說的,還寫一篇攻略?哈哈,如果你這么想,只能說明你too young to simple. 接觸過移動(dòng)端開發(fā)的同學(xué)可能都...
摘要:所以這種情況下是不符合點(diǎn)擊事件的定義的。,關(guān)于移動(dòng)端的點(diǎn)擊事件總結(jié)完了,可能你都沒想到一個(gè)簡(jiǎn)單的點(diǎn)擊事件會(huì)有那么多坑,如果你在工作中可能會(huì)涉及到移動(dòng)端開發(fā)的話,相信這篇文章還是值得你點(diǎn)贊和收藏的,畢竟是踩了那么多坑的經(jīng)驗(yàn)總結(jié)。 看標(biāo)題的時(shí)候你可能會(huì)想,點(diǎn)擊事件有什么好說的,還寫一篇攻略?哈哈,如果你這么想,只能說明你too young to simple. 接觸過移動(dòng)端開發(fā)的同學(xué)可能都...
摘要:像素像素是一個(gè)相對(duì)單位。相對(duì)不同屏幕,其實(shí)際像素大小不同。解決方案直接使用實(shí)現(xiàn)的終端適配有興趣的小伙伴可以看下的解決方案使用實(shí)現(xiàn)手淘頁(yè)面的終端適配地址移動(dòng)端適配單位的坑你知道多少關(guān)于移動(dòng)端布局的一些總結(jié) 網(wǎng)頁(yè)尺寸單位 百分比(%) 英寸(in) 厘米(cm) 毫米(mm) 磅數(shù)(pt) 12 點(diǎn)活字(pc) 字母高度一半(ex) 父級(jí)字體(em) 像素(px) 根元素字體(rem) ...
摘要:為此決定自研一個(gè)富文本編輯器。例如當(dāng)要轉(zhuǎn)化的對(duì)象有環(huán)存在時(shí)子節(jié)點(diǎn)屬性賦值了父節(jié)點(diǎn)的引用,為了關(guān)于函數(shù)式編程的思考作者李英杰,美團(tuán)金融前端團(tuán)隊(duì)成員。只有正確使用作用域,才能使用優(yōu)秀的設(shè)計(jì)模式,幫助你規(guī)避副作用。 JavaScript 專題之惰性函數(shù) JavaScript 專題系列第十五篇,講解惰性函數(shù) 需求 我們現(xiàn)在需要寫一個(gè) foo 函數(shù),這個(gè)函數(shù)返回首次調(diào)用時(shí)的 Date 對(duì)象,注意...
閱讀 1181·2021-09-27 13:34
閱讀 988·2021-09-13 10:25
閱讀 515·2019-08-30 15:52
閱讀 3453·2019-08-30 13:48
閱讀 655·2019-08-30 11:07
閱讀 2176·2019-08-29 16:23
閱讀 2001·2019-08-29 13:51
閱讀 2334·2019-08-26 17:42