当前位置:网站首页>Read zepto source code touch module
Read zepto source code touch module
2022-07-24 18:09:00 【Jiojio is learning le】
Everybody knows , For historical reasons , Click events on the mobile end will have 300ms Left right delay ,Zepto Of touch The module solves the problem of click delay on the mobile end , It also provides sliding swipe event .
read Zepto The source code series has been put in github On , welcome star: reading-zepto
Source version
The source code of this article is zepto1.2.0
GitBook
Implemented Events
;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown',
'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(eventName){
$.fn[eventName] = function(callback){
return this.on(eventName, callback) }
})- 1
- 2
- 3
- 4
As you can see from the above code ,Zepto The following events are implemented :
- swipe: Sliding events
- swipeLeft: Slide event to the left
- swipeRight: Slide event right
- swipeUp: Slide up event
- swipeDown: Slide down event
- doubleTap: Double click the event on the screen
- tap: Screen click events , Than
clickFaster event response - singleTap: Screen click event
- longTap: Long press event
And registered shortcuts for each event .
Internal methods
swipeDirection
function swipeDirection(x1, x2, y1, y2) {
return Math.abs(x1 - x2) >=
Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
}- 1
- 2
- 3
- 4
Return the sliding method .
x1 by x Axis Starting point coordinates , x2 by x Axis End coordinates , y1 by y Axis Starting point coordinates , y2 by y Axis End coordinates .
There are many sets of ternary expressions , The first comparison is x Axis and y Axis Sliding distance on , If x Axis Sliding distance ratio y Axis Big , Slide left and right , Otherwise, it is sliding up and down .
stay x Axis On , If the starting position is larger than the ending position , Slide left , return Left , Otherwise, slide to the right , return Right .
stay y Axis On , If the starting position is larger than the ending position , It is sliding upward , return Up , Otherwise, it is sliding downward , return Down .
longTap
var touch = {},
touchTimeout, tapTimeout, swipeTimeout, longTapTimeout,
longTapDelay = 750,
gesture
function longTap() {
longTapTimeout = null
if (touch.last) {
touch.el.trigger('longTap')
touch = {}
}
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
Trigger long press event .
touch The object stores the information in the touch process .
It's triggering longTap Before event , First save the variables of the timer longTapTimeout Release , If touch There is... In the object last , The trigger longTap event , last Save the last touch time . The final will be touch Reset to empty object , For the next use .
cancelLongTap
function cancelLongTap() {
if (longTapTimeout) clearTimeout(longTapTimeout)
longTapTimeout = null
}- 1
- 2
- 3
- 4
revoke longTap Event triggering .
If there is a trigger longTap Timer for , Clear the timer to stop longTap Event triggering .
Finally, we also need to longTapTimeout Variable set to null , Waiting for garbage collection .
cancelAll
function cancelAll() {
if (touchTimeout) clearTimeout(touchTimeout)
if (tapTimeout) clearTimeout(tapTimeout)
if (swipeTimeout) clearTimeout(swipeTimeout)
if (longTapTimeout) clearTimeout(longTapTimeout)
touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null
touch = {}
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
Clear the execution of all events .
In fact, it is to clear all relevant timers , The final will be touch Object is set to null .
isPrimaryTouch
function isPrimaryTouch(event){
return (event.pointerType == 'touch' ||
event.pointerType == event.MSPOINTER_TYPE_TOUCH)
&& event.isPrimary
}- 1
- 2
- 3
- 4
- 5
Whether it is the main contact .
When pointerType by touch also isPrimary by true when , Before the main contact . pointerType for touch 、 pen and mouse , Here we only deal with finger touch .
isPointerEventType
function isPointerEventType(e, type){
return (e.type == 'pointer'+type ||
e.type.toLowerCase() == 'mspointer'+type)
}- 1
- 2
- 3
- 4
Whether the trigger is pointerEvent .
In the lower version of mobile terminal IE Browser , only PointerEvent , It didn't happen TouchEvent , So we need this to judge .
Events trigger
Overall analysis
$(document).ready(function(){
var now, delta, deltaX = 0, deltaY = 0, firstTouch, _isPointerType
$(document)
.bind('MSGestureEnd', function(e){
...
})
.on('touchstart MSPointerDown pointerdown', function(e){
...
})
.on('touchmove MSPointerMove pointermove', function(e){
...
})
.on('touchend MSPointerUp pointerup', function(e){
...
})
.on('touchcancel MSPointerCancel pointercancel', cancelAll)
$(window).on('scroll', cancelAll)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
Let's start with a few variables ,now Used to save the current time , delta Used to save the time difference between two touches , deltaX For preservation x Axis Displacement on , deltaY To save y Axis Displacement on , firstTouch Save the information of the initial touch point , _isPointerType Save as pointerEvent The result of our judgment .
You can see from above , Zepto The event triggered , It's from touch 、 pointer perhaps IE Of guesture Incident , Calculated according to different situations . These events are bound to document On .
IE Gesture The handling of events
IE Gesture use , It takes three steps :
- Create gesture objects
- Specify the target element
- Specify the pointer to be processed during gesture recognition
if ('MSGesture' in window) {
gesture = new MSGesture()
gesture.target = document.body
}- 1
- 2
- 3
- 4
This code contains the first two steps .
on('touchstart MSPointerDown pointerdown', function(e){
...
if (gesture && _isPointerType) gesture.addPointer(e.pointerId)
}- 1
- 2
- 3
- 4
This paragraph is the third step , use addPointer Methods , Specify the pointer to be processed .
bind('MSGestureEnd', function(e){
var swipeDirectionFromVelocity =
e.velocityX > 1 ? 'Right' : e.velocityX < -1 ? 'Left' : e.velocityY > 1 ? 'Down' : e.velocityY < -1 ? 'Up' : null
if (swipeDirectionFromVelocity) {
touch.el.trigger('swipe')
touch.el.trigger('swipe'+ swipeDirectionFromVelocity)
}
})- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
The next step is to analyze gestures ,Gesture Only deal with swipe event .
velocityX and velocityY Respectively x Axis and y Axis Speed on . Here we use 1 or -1 Is the critical point , Judge swipe The direction of .
If swipe The direction of existence , The trigger swipe event , It also triggers directional swipe event .
start
on('touchstart MSPointerDown pointerdown', function(e){
if((_isPointerType = isPointerEventType(e, 'down')) &&
!isPrimaryTouch(e)) return
firstTouch = _isPointerType ? e : e.touches[0]
if (e.touches && e.touches.length === 1 && touch.x2) {
touch.x2 = undefined
touch.y2 = undefined
}
now = Date.now()
delta = now - (touch.last || now)
touch.el = $('tagName' in firstTouch.target ?
firstTouch.target : firstTouch.target.parentNode)
touchTimeout && clearTimeout(touchTimeout)
touch.x1 = firstTouch.pageX
touch.y1 = firstTouch.pageY
if (delta > 0 && delta <= 250) touch.isDoubleTap = true
touch.last = now
longTapTimeout = setTimeout(longTap, longTapDelay)
if (gesture && _isPointerType) gesture.addPointer(e.pointerId)
})- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
Filter out non touch events
if((_isPointerType = isPointerEventType(e, 'down')) &&
!isPrimaryTouch(e)) return
firstTouch = _isPointerType ? e : e.touches[0]- 1
- 2
- 3
There will also be isPointerEventType The judgment result of is saved to _isPointerType in , It is used to judge whether it is PointerEvent .
The judgment here is actually only dealing with PointerEvent and TouchEvent , also TouchEvent Of isPrimary It has to be for true .
because TouchEvent Support multi touch , Here, only the first point touched is saved firstTouch Variable .
Reset the end coordinates
if (e.touches && e.touches.length === 1 && touch.x2) {
touch.x2 = undefined
touch.y2 = undefined
}- 1
- 2
- 3
- 4
If you still need to record , The end coordinates need to be updated .
Under normal circumstances ,touch The object will be touchEnd perhaps cancel Empty it when it's time , But if the user calls preventDefault etc. , There may be no emptying .
There is a little bit unclear here , Why only in touches It is emptied only during single point operation ? Don't you need to empty multiple touch points ?
Record the information of the touch point
now = Date.now()
delta = now - (touch.last || now)
touch.el = $('tagName' in firstTouch.target ?
firstTouch.target : firstTouch.target.parentNode)
touchTimeout && clearTimeout(touchTimeout)
touch.x1 = firstTouch.pageX
touch.y1 = firstTouch.pageY- 1
- 2
- 3
- 4
- 5
- 6
- 7
now Used to save the current time .
delta Used to save the time interval between two clicks , Used to handle double-click events .
touch.el Used to save the target element , Here's a judgment , If target When it is not a label node , Take the parent node as the target element . This will appear when you click on the pseudo class element .
If touchTimeout There is , Then clear the timer , Avoid repetitive triggers .
touch.x1 and touch.y1 Keep separately x Axis Coordinates and y Axis coordinate .
Double-click the event
if (delta > 0 && delta <= 250) touch.isDoubleTap = true- 1
You can see it very clearly , Zepto The time interval between two clicks is less than 250ms when , As doubleTap Event handling , take isDoubleTap Set to true .
Long press event
touch.last = now
longTapTimeout = setTimeout(longTap, longTapDelay)- 1
- 2
take touch.last Set to current time . In this way, the time difference between two clicks can be recorded .
At the same time, long press the event timer , As you can see from the code above , Long press the event in 750ms Post trigger .
move
on('touchmove MSPointerMove pointermove', function(e){
if((_isPointerType = isPointerEventType(e, 'move')) &&
!isPrimaryTouch(e)) return
firstTouch = _isPointerType ? e : e.touches[0]
cancelLongTap()
touch.x2 = firstTouch.pageX
touch.y2 = firstTouch.pageY
deltaX += Math.abs(touch.x1 - touch.x2)
deltaY += Math.abs(touch.y1 - touch.y2)
})- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
move The incident dealt with two things , First, record the coordinates of the end point , One is to calculate the displacement between the starting point and the end point .
Note that here you also call cancelLongTap Cleared the long press timer , Avoid triggering long press events . Because there is movement , It's definitely not a long press .
end
on('touchend MSPointerUp pointerup', function(e){
if((_isPointerType = isPointerEventType(e, 'up')) &&
!isPrimaryTouch(e)) return
cancelLongTap()
if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) ||
(touch.y2 && Math.abs(touch.y1 - touch.y2) > 30))
swipeTimeout = setTimeout(function() {
if (touch.el){
touch.el.trigger('swipe')
touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)))
}
touch = {}
}, 0)
else if ('last' in touch)
if (deltaX < 30 && deltaY < 30) {
tapTimeout = setTimeout(function() {
var event = $.Event('tap')
event.cancelTouch = cancelAll
if (touch.el) touch.el.trigger(event)
if (touch.isDoubleTap) {
if (touch.el) touch.el.trigger('doubleTap')
touch = {}
}
else {
touchTimeout = setTimeout(function(){
touchTimeout = null
if (touch.el) touch.el.trigger('singleTap')
touch = {}
}, 250)
}
}, 0)
} else {
touch = {}
}
deltaX = deltaY = 0
})- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
swipe
cancelLongTap()
if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) ||
(touch.y2 && Math.abs(touch.y1 - touch.y2) > 30))
swipeTimeout = setTimeout(function() {
if (touch.el){
touch.el.trigger('swipe')
touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)))
}
touch = {}
}, 0)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
Get into end when , Clear now longTap Timer execution .
You can see , The distance between the starting point and the ending point exceeds 30 when , Will be judged as swipe Sliding events .
After triggering swipe After the event , Immediately trigger swipe event .
Be careful ,swipe The incident is not end Triggered immediately when a series of events are triggered , It's set up a 0ms Timer for , Let the event trigger asynchronously , What's the use of this ? I'll talk about it later .
tap
else if ('last' in touch)
if (deltaX < 30 && deltaY < 30) {
tapTimeout = setTimeout(function() {
var event = $.Event('tap')
event.cancelTouch = cancelAll
if (touch.el) touch.el.trigger(event)
}, 0)
} else {
touch = {}
}
deltaX = deltaY = 0- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
Finally, I see the point , First judgement last Whether there is , from start Can be seen in , If it triggers start , last There must be , But if a long press event is triggered ,touch The object is emptied , At this time, it will not trigger tap event .
If not swipe event , There is no such thing as last , Then only touch Empty , No event is triggered .
In the end will deltaX and deltaY Reset to 0 .
Trigger tap When an event is , Will be in event Medium plus cancelTouch Method , The outside world can cancel the execution of all events through this method .
It's also used here setTimeout Asynchronous trigger event .
doubleTap
if (touch.isDoubleTap) {
if (touch.el) touch.el.trigger('doubleTap')
touch = {}
}- 1
- 2
- 3
- 4
This isDoubleTap stay start It's certain , It has been analyzed above , stay end Is triggered when doubleTap event .
therefore , You can know , It's triggering doubleTap The event will be triggered twice tap event .
singleTap
touchTimeout = setTimeout(function(){
touchTimeout = null
if (touch.el) touch.el.trigger('singleTap')
touch = {}
}, 250)- 1
- 2
- 3
- 4
- 5
If not doubleTap , Will be in tap Event triggered 250ms after , Trigger singleTap event .
cancel
.on('touchcancel MSPointerCancel pointercancel', cancelAll)- 1
On receiving cancel When an event is , call cancelAll Method , Cancel the triggering of all events .
scroll
$(window).on('scroll', cancelAll)- 1
From the previous analysis, we can see that , All event triggers are asynchronous .
Because in scroll When , It must be that you just want to respond to rolling events , Asynchronously triggered in scroll And external calls cancelTouch When the method is used , You can cancel the event .
边栏推荐
- ROC and AUC details of the recommended system
- Mac database management software Navicat premium essentials mac
- Win10 super good-looking mouse theme, you also try it
- sklearn 的模型保存与加载使用
- Bib | mol2context vec: context aware deep network model learning molecular representation for drug discovery
- Guess JWT keyword
- Blackmagic Fusion Studio 18
- [leetcode] 30. Concatenate substrings of all words
- 邻接表的定义和存储以及有向图无向图的邻接存储
- 0701~放假总结
猜你喜欢

关于接口的写法 1链式判读 ?. 2方法执行 (finally)一定会执行

Icml2022 Best Paper Award: learning protein reverse folding from millions of predicted structures

redis集群的三种方式

ROC and AUC details of the recommended system

C language programming training topics: K characters in left-handed string, little Lele and Euclidean, printing arrow pattern, civil servant interview, poplar matrix

6126. 设计食物评分系统

Use of jumpserver

PXE高效批量网络装机

Shengxin commonly used analysis graphics drawing 02 -- unlock the essence of volcano map!

【网络安全】网站中间件存在的解析漏洞
随机推荐
简单测试JS代码
移动端实现0.5px的实用方案
Win10 super good-looking mouse theme, you also try it
Three ways of redis cluster
0630~ professional quality course
Three ways of redis cluster
How to quickly upload files to Google Lab
《STL源码剖析》应该怎样读?
Quickly complete the unit test junit4 setting of intelij idea
After separation, the impression notes are still difficult to live, but there are many coquettish operations
Go to bed capacity exchange
[leetcode] 30. Concatenate substrings of all words
Simple test JS code
Brats18 - Multimodal MR image brain tumor segmentation challenge continued
C language custom type explanation - Consortium
(mandatory) override equals must override hashcode (principle analysis)
SV casts and constants
0629 ~ SaaS platform design ~ global exception handling
Use of jumpserver
C language custom types - Enumeration