fastclick-源码解析
生活随笔
收集整理的這篇文章主要介紹了
fastclick-源码解析
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
;
(function() {'use strict';//構(gòu)造函數(shù)function FastClick(layer, options) {var oldOnClick;options = options || {};//是否開始追蹤click事件this.trackingClick = false;//存儲(chǔ)第一次按下時(shí)間戳this.trackingClickStart = 0;//目標(biāo)元素this.targetElement = null;//存放坐標(biāo)值Xthis.touchStartX = 0;//存放坐標(biāo)值Ythis.touchStartY = 0;//主要hack iOS4下的一個(gè)怪異問(wèn)題this.lastTouchIdentifier = 0;//用于區(qū)分是click還是Touchmove,若出點(diǎn)移動(dòng)超過(guò)該值則視為touchmovethis.touchBoundary = options.touchBoundary || 10;// 綁定了FastClick的元素,一般是是bodythis.layer = layer;//雙擊最小點(diǎn)擊時(shí)間差this.tapDelay = options.tapDelay || 200;//長(zhǎng)按最大時(shí)間this.tapTimeout = options.tapTimeout || 700;//如果是屬于不需要處理的元素類型,則直接返回if(FastClick.notNeeded(layer)) {return;}//語(yǔ)法糖,兼容一些用不了 Function.prototype.bind 的舊安卓//所以后面不走 layer.addEventListener('click', this.onClick.bind(this), true);function bind(method, context) {return function() {return method.apply(context, arguments);};}var methods = ['onMouse', 'onClick', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel'];var context = this;for(var i = 0, l = methods.length; i < l; i++) {context[methods[i]] = bind(context[methods[i]], context);}//安卓則做額外處理if(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);// 兼容不支持 stopImmediatePropagation 的瀏覽器(比如 Android 2)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') {//留意這里 callback.hijacked 中會(huì)判斷 event.propagationStopped 是否為真來(lái)確保(安卓的onMouse事件)只執(zhí)行一次//在 onMouse 事件里會(huì)給 event.propagationStopped 賦值 trueadv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {if(!event.propagationStopped) {callback(event);}}), capture);} else {adv.call(layer, type, callback, capture);}};}// 如果layer直接在DOM上寫了 onclick 方法,那我們需要把它替換為 addEventListener 綁定形式if(typeof layer.onclick === 'function') {oldOnClick = layer.onclick;layer.addEventListener('click', function(event) {oldOnClick(event);}, false);layer.onclick = null;}}/*** Windows Phone 8.1 fakes user agent string to look like Android and iPhone.** @type boolean*/var deviceIsWindowsPhone = navigator.userAgent.indexOf("Windows Phone") >= 0;/*** Android requires exceptions.** @type boolean*/var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0 && !deviceIsWindowsPhone;/*** iOS requires exceptions.** @type boolean*/var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent) && !deviceIsWindowsPhone;/*** iOS 4 requires an exception for select elements.** @type boolean*/var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);/*** iOS 6.0-7.* requires the target element to be manually derived** @type boolean*/var deviceIsIOSWithBadTarget = deviceIsIOS && (/OS [6-7]_\d/).test(navigator.userAgent);/*** BlackBerry requires exceptions.** @type boolean*/var deviceIsBlackBerry10 = navigator.userAgent.indexOf('BB10') > 0;//判斷元素是否要保留穿透功能FastClick.prototype.needsClick = function(target) {switch(target.nodeName.toLowerCase()) {// disabled的inputcase 'button':case 'select':case 'textarea':if(target.disabled) {return true;}break;case 'input':// file組件必須通過(guò)原生click事件點(diǎn)擊才有效if((deviceIsIOS && target.type === 'file') || target.disabled) {return true;}break;case 'label':case 'iframe':case 'video':return true;}//元素帶了名為“bneedsclick”的class也返回truereturn(/\bneedsclick\b/).test(target.className);};//判斷給定元素是否需要通過(guò)合成click事件來(lái)模擬聚焦FastClick.prototype.needsFocus = function(target) {switch(target.nodeName.toLowerCase()) {case 'textarea':return true;case 'select':return !deviceIsAndroid; //iOS下的select得走穿透點(diǎn)擊才行case 'input':switch(target.type) {case 'button':case 'checkbox':case 'file':case 'image':case 'radio':case 'submit':return false;}return !target.disabled && !target.readOnly;default://帶有名為“bneedsfocus”的class則返回truereturn(/\bneedsfocus\b/).test(target.className);}};//合成一個(gè)click事件并在指定元素上觸發(fā)FastClick.prototype.sendClick = function(targetElement, event) {var clickEvent, touch;// 在一些安卓機(jī)器中,得讓頁(yè)面所存在的 activeElement(聚焦的元素,比如input)失焦,否則合成的click事件將無(wú)效if(document.activeElement && document.activeElement !== targetElement) {document.activeElement.blur();}touch = event.changedTouches[0];// 合成(Synthesise) 一個(gè) click 事件// 通過(guò)一個(gè)額外屬性確保它能被追蹤(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; // fastclick的內(nèi)部變量,用來(lái)識(shí)別click事件是原生還是合成的targetElement.dispatchEvent(clickEvent); //立即觸發(fā)其click事件};FastClick.prototype.determineEventType = function(targetElement) {//安卓設(shè)備下 Select 無(wú)法通過(guò)合成的 click 事件被展開,得改為 mousedownif(deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {return 'mousedown';}return 'click';};//設(shè)置元素聚焦事件FastClick.prototype.focus = function(targetElement) {var length;// 組件建議通過(guò)setSelectionRange(selectionStart, selectionEnd)來(lái)設(shè)定光標(biāo)范圍(注意這樣還沒(méi)有聚焦// 要等到后面觸發(fā) sendClick 事件才會(huì)聚焦)// 另外 iOS7 下有些input元素(比如 date datetime month) 的 selectionStart 和 selectionEnd 特性是沒(méi)有整型值的,// 導(dǎo)致會(huì)拋出一個(gè)關(guān)于 setSelectionRange 的模糊錯(cuò)誤,它們需要改用 focus 事件觸發(fā)if(deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month') {length = targetElement.value.length;targetElement.setSelectionRange(length, length);} else {//直接觸發(fā)其focus事件targetElement.focus();}};/*** 檢查target是否一個(gè)滾動(dòng)容器里的子元素,如果是則給它加個(gè)標(biāo)記*/FastClick.prototype.updateScrollParent = function(targetElement) {var scrollParent, parentElement;scrollParent = targetElement.fastClickScrollParent;// Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the// target element was moved to another parent.if(!scrollParent || !scrollParent.contains(targetElement)) {parentElement = targetElement;do {if(parentElement.scrollHeight > parentElement.offsetHeight) {scrollParent = parentElement;targetElement.fastClickScrollParent = parentElement;break;}parentElement = parentElement.parentElement;} while (parentElement);}// 給滾動(dòng)容器加個(gè)標(biāo)志fastClickLastScrollTop,值為其當(dāng)前垂直滾動(dòng)偏移if(scrollParent) {scrollParent.fastClickLastScrollTop = scrollParent.scrollTop;}};/*** 返回目標(biāo)元素*/FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {// 一些較老的瀏覽器,target 可能會(huì)是一個(gè)文本節(jié)點(diǎn),得返回其DOM節(jié)點(diǎn)if(eventTarget.nodeType === Node.TEXT_NODE) {return eventTarget.parentNode;}return eventTarget;};FastClick.prototype.onTouchStart = function(event) {var targetElement, touch, selection;// 多指觸控的手勢(shì)則忽略if(event.targetTouches.length > 1) {return true;}targetElement = this.getTargetElementFromEventTarget(event.target); //一些較老的瀏覽器,target 可能會(huì)是一個(gè)文本節(jié)點(diǎn),得返回其DOM節(jié)點(diǎn)touch = event.targetTouches[0];if(deviceIsIOS) { //IOS處理// 若用戶已經(jīng)選中了一些內(nèi)容(比如選中了一段文本打算復(fù)制),則忽略selection = window.getSelection();if(selection.rangeCount && !selection.isCollapsed) {return true;}if(!deviceIsIOS4) { //是否IOS4//怪異特性處理——若click事件回調(diào)打開了一個(gè)alert/confirm,用戶下一次tap頁(yè)面的其它地方時(shí),新的touchstart和touchend//事件會(huì)擁有同一個(gè)touch.identifier(新的 touch event 會(huì)跟上一次觸發(fā)alert點(diǎn)擊的 touch event 一樣),//為避免將新的event當(dāng)作之前的event導(dǎo)致問(wèn)題,這里需要禁用默認(rèn)事件//另外chrome的開發(fā)工具啟用'Emulate touch events'后,iOS UA下的 identifier 會(huì)變成0,所以要做容錯(cuò)避免調(diào)試過(guò)程也被禁用事件了if(touch.identifier && touch.identifier === this.lastTouchIdentifier) {event.preventDefault();return false;}this.lastTouchIdentifier = touch.identifier;// 如果target是一個(gè)滾動(dòng)容器里的一個(gè)子元素(使用了 -webkit-overflow-scrolling: touch) ,而且滿足:// 1) 用戶非常快速地滾動(dòng)外層滾動(dòng)容器// 2) 用戶通過(guò)tap停止住了這個(gè)快速滾動(dòng)// 這時(shí)候最后的'touchend'的event.target會(huì)變成用戶最終手指下的那個(gè)元素// 所以當(dāng)快速滾動(dòng)開始的時(shí)候,需要做檢查target是否滾動(dòng)容器的子元素,如果是,做個(gè)標(biāo)記// 在touchend時(shí)檢查這個(gè)標(biāo)記的值(滾動(dòng)容器的scrolltop)是否改變了,如果是則說(shuō)明頁(yè)面在滾動(dòng)中,需要取消fastclick處理this.updateScrollParent(targetElement);}}this.trackingClick = true; //做個(gè)標(biāo)志表示開始追蹤click事件了this.trackingClickStart = event.timeStamp; //標(biāo)記下touch事件開始的時(shí)間戳this.targetElement = targetElement;//標(biāo)記touch起始點(diǎn)的頁(yè)面偏移值this.touchStartX = touch.pageX;this.touchStartY = touch.pageY;// this.lastClickTime 是在 touchend 里標(biāo)記的事件時(shí)間戳// this.tapDelay 為常量 200 (ms)// 此舉用來(lái)避免 phantom 的雙擊(200ms內(nèi)快速點(diǎn)了兩次)觸發(fā) click// 反正200ms內(nèi)的第二次點(diǎn)擊會(huì)禁止觸發(fā)點(diǎn)擊的默認(rèn)事件if((event.timeStamp - this.lastClickTime) < this.tapDelay) {event.preventDefault();}return true;};//判斷是否移動(dòng)了//this.touchBoundary是常量,值為10//如果touch已經(jīng)移動(dòng)了10個(gè)偏移量單位,則應(yīng)當(dāng)作為移動(dòng)事件處理而非click事件FastClick.prototype.touchHasMoved = function(event) {var touch = event.changedTouches[0],boundary = this.touchBoundary;if(Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) {return true;}return false;};FastClick.prototype.onTouchMove = function(event) {//不是需要被追蹤click的事件則忽略if(!this.trackingClick) {return true;}// 如果target突然改變了,或者用戶其實(shí)是在移動(dòng)手勢(shì)而非想要click// 則應(yīng)該清掉this.trackingClick和this.targetElement,告訴后面的事件你們也不用處理了if(this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {this.trackingClick = false;this.targetElement = null;}return true;};//找到label標(biāo)簽所映射的組件,方便讓用戶點(diǎn)label的時(shí)候直接激活該組件FastClick.prototype.findControl = function(labelElement) {// 有緩存則直接讀緩存著的if(labelElement.control !== undefined) {return labelElement.control;}// 獲取指向的組件if(labelElement.htmlFor) {return document.getElementById(labelElement.htmlFor);}// 沒(méi)有for屬性則激活頁(yè)面第一個(gè)組件(labellable 元素)return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea');};FastClick.prototype.onTouchEnd = function(event) {var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;if(!this.trackingClick) {return true;}// 避免 phantom 的雙擊(200ms內(nèi)快速點(diǎn)了兩次)觸發(fā) click// 我們?cè)?ontouchstart 里已經(jīng)做過(guò)一次判斷了(僅僅禁用默認(rèn)事件),這里再做一次判斷if((event.timeStamp - this.lastClickTime) < this.tapDelay) {this.cancelNextClick = true; //該屬性會(huì)在 onMouse 事件中被判斷,為true則徹底禁用事件和冒泡return true;}//this.tapTimeout是常量,值為700//識(shí)別是否為長(zhǎng)按事件,如果是(大于700ms)則忽略if((event.timeStamp - this.trackingClickStart) > this.tapTimeout) {return true;}// 得重置為false,避免input事件被意外取消// 例子見(jiàn) https://github.com/ftlabs/fastclick/issues/156this.cancelNextClick = false;this.lastClickTime = event.timeStamp; //標(biāo)記touchend時(shí)間,方便下一次的touchstart做雙擊校驗(yàn)trackingClickStart = this.trackingClickStart;//重置 this.trackingClick 和 this.trackingClickStartthis.trackingClick = false;this.trackingClickStart = 0;// iOS 6.0-7.*版本下有個(gè)問(wèn)題 —— 如果layer處于transition或scroll過(guò)程,event所提供的target是不正確的// 所以咱們得重找 targetElement(這里通過(guò) document.elementFromPoint 接口來(lái)尋找)if(deviceIsIOSWithBadTarget) { //iOS 6.0-7.*版本touch = event.changedTouches[0]; //手指離開前的觸點(diǎn)// 有些情況下 elementFromPoint 里的參數(shù)是預(yù)期外/不可用的, 所以還得避免 targetElement 為 nulltargetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;// target可能不正確需要重找,但fastClickScrollParent是不會(huì)變的targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;}targetTagName = targetElement.tagName.toLowerCase();if(targetTagName === 'label') { //是label則激活其指向的組件forElement = this.findControl(targetElement);if(forElement) {this.focus(targetElement);//安卓直接返回(無(wú)需合成click事件觸發(fā),因?yàn)辄c(diǎn)擊和激活元素不同,不存在點(diǎn)透)if(deviceIsAndroid) {return false;}targetElement = forElement;}} else if(this.needsFocus(targetElement)) { //非label則識(shí)別是否需要focus的元素//手勢(shì)停留在組件元素時(shí)長(zhǎng)超過(guò)100ms,則置空this.targetElement并返回//(而不是通過(guò)調(diào)用this.focus來(lái)觸發(fā)其聚焦事件,走的原生的click/focus事件觸發(fā)流程)//這也是為何文章開頭提到的問(wèn)題中,稍微久按一點(diǎn)(超過(guò)100ms)textarea是可以把光標(biāo)定位在正確的地方的原因//另外iOS下有個(gè)意料之外的bug——如果被點(diǎn)擊的元素所在文檔是在iframe中的,手動(dòng)調(diào)用其focus的話,//會(huì)發(fā)現(xiàn)你往其中輸入的text是看不到的(即使value做了更新),so這里也直接返回if((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) {this.targetElement = null;return false;}this.focus(targetElement);this.sendClick(targetElement, event); //立即觸發(fā)其click事件,而無(wú)須等待300ms//iOS4下的 select 元素不能禁用默認(rèn)事件(要確保它能被穿透),否則不會(huì)打開select目錄//有時(shí)候 iOS6/7 下(VoiceOver開啟的情況下)也會(huì)如此if(!deviceIsIOS || targetTagName !== 'select') {this.targetElement = null;event.preventDefault();}return false;}if(deviceIsIOS && !deviceIsIOS4) {// 滾動(dòng)容器的垂直滾動(dòng)偏移改變了,說(shuō)明是容器在做滾動(dòng)而非點(diǎn)擊,則忽略scrollParent = targetElement.fastClickScrollParent;if(scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {return true;}}// 查看元素是否無(wú)需處理的白名單內(nèi)(比如加了名為“needsclick”的class)// 不是白名單的則照舊預(yù)防穿透處理,立即觸發(fā)合成的click事件if(!this.needsClick(targetElement)) {event.preventDefault();this.sendClick(targetElement, event);}return false;};FastClick.prototype.onTouchCancel = function() {this.trackingClick = false;this.targetElement = null;};//用于決定是否允許穿透事件(觸發(fā)layer的click默認(rèn)事件)FastClick.prototype.onMouse = function(event) {// touch事件一直沒(méi)觸發(fā)if(!this.targetElement) {return true;}if(event.forwardedTouchEvent) { //觸發(fā)的click事件是合成的return true;}// 編程派生的事件所對(duì)應(yīng)元素事件可以被允許// 確保其沒(méi)執(zhí)行過(guò) preventDefault 方法(event.cancelable 不為 true)即可if(!event.cancelable) {return true;}// 需要做預(yù)防穿透處理的元素,或者做了快速(200ms)雙擊的情況if(!this.needsClick(this.targetElement) || this.cancelNextClick) {//停止當(dāng)前默認(rèn)事件和冒泡if(event.stopImmediatePropagation) {event.stopImmediatePropagation();} else {// 不支持 stopImmediatePropagation 的設(shè)備(比如Android 2)做標(biāo)記,// 確保該事件回調(diào)不會(huì)執(zhí)行(見(jiàn)126行)event.propagationStopped = true;}// 取消事件和冒泡event.stopPropagation();event.preventDefault();return false;}//允許穿透return true;};//click事件常規(guī)都是touch事件衍生來(lái)的,也排在touch后面觸發(fā)。//對(duì)于那些我們?cè)趖ouch事件過(guò)程沒(méi)有禁用掉默認(rèn)事件的event來(lái)說(shuō),我們還需要在click的捕獲階段進(jìn)一步//做判斷決定是否要禁掉點(diǎn)擊事件(防穿透)FastClick.prototype.onClick = function(event) {var permitted;// 如果還有 trackingClick 存在,可能是某些UI事件阻塞了touchEnd 的執(zhí)行if(this.trackingClick) {this.targetElement = null;this.trackingClick = false;return true;}// 依舊是對(duì) iOS 怪異行為的處理 —— 如果用戶點(diǎn)擊了iOS模擬器里某個(gè)表單中的一個(gè)submit元素// 或者點(diǎn)擊了彈出來(lái)的鍵盤里的“Go”按鈕,會(huì)觸發(fā)一個(gè)“偽”click事件(target是一個(gè)submit-type的input元素)if(event.target.type === 'submit' && event.detail === 0) {return true;}permitted = this.onMouse(event);if(!permitted) { //如果點(diǎn)擊是被允許的,將this.targetElement置空可以確保onMouse事件里不會(huì)阻止默認(rèn)事件this.targetElement = null;}//沒(méi)有多大意義return permitted;};//銷毀Fastclick所注冊(cè)的監(jiān)聽(tīng)事件。是給外部實(shí)例去調(diào)用的FastClick.prototype.destroy = function() {var layer = this.layer;if(deviceIsAndroid) {layer.removeEventListener('mouseover', this.onMouse, true);layer.removeEventListener('mousedown', this.onMouse, true);layer.removeEventListener('mouseup', this.onMouse, true);}layer.removeEventListener('click', this.onClick, true);layer.removeEventListener('touchstart', this.onTouchStart, false);layer.removeEventListener('touchmove', this.onTouchMove, false);layer.removeEventListener('touchend', this.onTouchEnd, false);layer.removeEventListener('touchcancel', this.onTouchCancel, false);};//是否沒(méi)必要使用到 Fastclick 的檢測(cè)FastClick.notNeeded = function(layer) {var metaViewport;var chromeVersion;var blackberryVersion;var firefoxVersion;// 不支持觸摸的設(shè)備if(typeof window.ontouchstart === 'undefined') {return true;}// 獲取Chrome版本號(hào),若非Chrome則返回0chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [, 0])[1];if(chromeVersion) {if(deviceIsAndroid) { //安卓metaViewport = document.querySelector('meta[name=viewport]');if(metaViewport) {// 安卓下,帶有 user-scalable="no" 的 meta 標(biāo)簽的 chrome 是會(huì)自動(dòng)禁用 300ms 延遲的,所以無(wú)需 Fastclickif(metaViewport.content.indexOf('user-scalable=no') !== -1) {return true;}// 安卓Chrome 32 及以上版本,若帶有 width=device-width 的 meta 標(biāo)簽也是無(wú)需 FastClick 的if(chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) {return true;}}// 其它的就肯定是桌面級(jí)的 Chrome 了,更不需要 FastClick 啦} else {return true;}}if(deviceIsBlackBerry10) { //黑莓,和上面安卓同理,就不寫注釋了blackberryVersion = navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/);if(blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3) {metaViewport = document.querySelector('meta[name=viewport]');if(metaViewport) {if(metaViewport.content.indexOf('user-scalable=no') !== -1) {return true;}if(document.documentElement.scrollWidth <= window.outerWidth) {return true;}}}}// 帶有 -ms-touch-action: none / manipulation 特性的 IE10 會(huì)禁用雙擊放大,也沒(méi)有 300ms 時(shí)延if(layer.style.msTouchAction === 'none' || layer.style.touchAction === 'manipulation') {return true;}// Firefox檢測(cè),同上firefoxVersion = +(/Firefox\/([0-9]+)/.exec(navigator.userAgent) || [, 0])[1];if(firefoxVersion >= 27) {metaViewport = document.querySelector('meta[name=viewport]');if(metaViewport && (metaViewport.content.indexOf('user-scalable=no') !== -1 || document.documentElement.scrollWidth <= window.outerWidth)) {return true;}}// IE11 推薦使用沒(méi)有“-ms-”前綴的 touch-action 樣式特性名if(layer.style.touchAction === 'none' || layer.style.touchAction === 'manipulation') {return true;}return false;};FastClick.attach = function(layer, options) {return new FastClick(layer, options);};if(typeof define === 'function' && typeof define.amd === 'object' && define.amd) {// AMD. Register as an anonymous module.define(function() {return FastClick;});} else if(typeof module !== 'undefined' && module.exports) {module.exports = FastClick.attach;module.exports.FastClick = FastClick;} else {window.FastClick = FastClick;}
}());
復(fù)制代碼<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Demo</title><script src="./fastclick.js"></script><style>div {width: 200px;background: red;Ymargin: 0 auto;height: 200px;color: wheat;font-size: 25px;display: flex;justify-content: center;align-items: center;}</style></head><body><div id="main">FastClick</div><script>FastClick.attach(document.body);document.getElementById("main").addEventListener("click", function(event) {console.log(event.target.innerText)}, false)</script></body></html>
復(fù)制代碼
總結(jié)
以上是生活随笔為你收集整理的fastclick-源码解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【动画演示软件】Focusky教程 |
- 下一篇: 五分钟理解原码补码反码和移码