小编给大家分享一下怎么使用JavaScript实现手势库,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
JavaScript的特点
1.JavaScript主要用来向HTML页面添加交互行为。2.JavaScript可以直接嵌入到HTML页面,但写成单独的js文件有利于结构和行为的分离。3.JavaScript具有跨平台特性,在绝大多数浏览器的支持下,可以在多种平台下运行。
Start 事件
首先我们会触发一个 start 事件,也就是当我们手指触摸到屏幕时第一个触发的事件。这时会有三种情况:
手指松开
会触发 end 事件,这样就构成一个
tap
点击的行为通过监听 end 事件来实现即可
手指拖动超过 10 px
这种就是
pan start
拖动的行为我们可以在 move 事件判断当前与上一个触点的距离
手指停留在当前位置超过 0.5s
这种就是
press start
按压的行为我们可以添加一个 setTimeout 来实现
Press 事件
所以我们第一步就是在 start
函数中加入一个 setTimout
的 handler 处理程序。
let handler;let start = point => { handler = setTimeout(() => { console.log('presss '); }, 500);};
一般来说 press
是我们比较常见的一个行为。但是实际上这里是 press start 事件,后面还会跟随着一个 press end 的事件。我们也可以统称这个为 press
事件,然后这个手势库的使用者只需要监听这个 press
事件即可,极少的情况下是需要监听 press end
事件的。
这里我们需要注意的是,当我们触发其他的事件的时候,这个 500 毫秒的 setTimout 是有可能会被取消掉的。所以我们需要给这段逻辑一个 handler
,并且放在全局作用域中,让其他事件可以获取到这个变量,并且可使用它取消掉这个处理逻辑。
Pan 事件
接下来我们就去监听移动 10px 的 pan
事件,这里就需要我们记录一开始用户触摸屏幕时的 x 和 y 坐标,当用户移动手指的时候,持续计算新移动到的位置与初始位置的距离。如果这个距离超过了 10px 就可以触发我们的 pan start
的事件了。
所以首先我们需要在 start 函数中加入 startX
和 startY
的坐标记录,这里要注意的是,因为这两个值都是会在多个地方被使用的,所以也是需要在全局作用域中声明。
然后在 move 函数中计算当前触点与起点的直径距离。这里我们需要用到数学中的直径运算公式 z 2 x^2 + y^2 = z^2x 2 +y 2 =z 2 ,而这里面的 x 是 当前触点的 x 坐标 - 起点的 x 坐标 的 x 轴的距离, y 就是 当前出点的 y 坐标 - 起点的 y 坐标 运算出来的 y 轴的距离。最终两个距离二次幂相加就是直径距离的二次幂。
在代码中我们一般都会尽量避免使用根号运算,因为根号运算会对性能有一定的影响。我们知道最终要判断的是直径距离是否是大于一个固定的 10px。那就是说 z = 10,而 z 的二次幂就是 100,所以我们直接判断这个直径距离是否大于 100 即可。
这里还有一个需要注意的,就是当我们手指移动超过 10px 之后,如果我们手指没有离开屏幕而是往回移动了,这样的话我们距离起点已经不够 10px了。但是这个其实也是算 pan 事件,因为我们确实有移动超过 10px 距离,超过这个距离之后所有的移动都是属于 pan 事件。
所以我们需要一个 isPan
的状态,第一次移动超出 10px 的时候,就会触发 pan-start
事件,并且把 isPan
置为 true,而后面的所有移动都会触发 pan
事件。
根据我们上面讲到的 press
事件,如果我们按下手指后 0.5 秒内出现了移动,那么 press
事件就会被取消。所以这里我们就需要 clearTimeout
把 pressstart
的 handler
给清楚掉。
let handler;let startX, startY;let isPan = false;let start = point => { (startX = point.clientX), (startY = point.clientY); isPan = false; handler = setTimeout(() => { console.log('pressstart'); }, 500);};let move = point => { let dx = point.clientX - startX, dy = point.clientY - startY; let d = dx ** 2 + dy ** 2; if (!isPan && d > 100) { isPan = true; console.log('pan-start'); clearTimeout(handler); } if (isPan) { console.log(dx, dy); console.log('pan'); }};
Tap 事件
Tap 的这个逻辑我们可以在 end 事件里面去检查。首先我们默认有一个 isTap
等于 true 的状态,如果我们触发了 pan 事件的话,那就不会去触发 tap 的逻辑了,所以 tap 和 pan 是互斥的关系。但是为了不让它们变得很耦合,所以我们不使用原有的 isPan 作为判断状态,而是另外声明一个 isTap
的状态来记录。
这里我们 tap 和 pan 都有单独的状态,那么我们 press 也不例外,所以也给 press 加上一个 isPress
的状态,它的默认值是 false。如果我们 0.5 秒的定时器被触发了,isPress
也就会变成 true。
既然我们给每个事件都加入了状态,那么这里我们就给每一个事件触发的时候设置好这些状态的值。
press 时
isTap = false
isPan = false
isPress = true
pan 时
isTap = false
isPan = true
isPress = false
tap 时
isTap = true
isPan = false
isPress = false
如果我们发现用户没有移动,也没有按住触屏超过 0.5 秒,当用户离开屏幕时就会调用 end 函数,这个时候我们就可以认定用户的操作就是 tap。这里我们要注意的是,我们 press 的 0.5 秒定时器是没有被关闭的,所以我们在 isTap 的逻辑中需要 clearTimeout(handler)
。
说到取消 press 定时器,其实我们 handler 的回调函数中,也需要做一个保护代码逻辑,在触发了 press-start 之后,我们需要保证每次点击屏幕只会触发一次,所以在 setTimout 的回调函数中的最后,我们需要加上 handler = null
。这样只要 press-start 触发了,就不会再被触发。
let handler;let startX, startY;let isPan = false, isPress = false, isTap = false;let start = point => { (startX = point.clientX), (startY = point.clientY); isPan = false; isTap = true; isPress = false; handler = setTimeout(() => { isPan = false; isTap = false; isPress = true; console.log('press-start'); handler = null; }, 500);};let move = point => { let dx = point.clientX - startX, dy = point.clientY - startY; let d = dx ** 2 + dy ** 2; if (!isPan && d > 100) { isPan = true; isTap = false; isPress = false; console.log('pan-start'); clearTimeout(handler); } if (isPan) { console.log(dx, dy); console.log('pan'); }};let end = point => { if (isTap) { console.log('tap'); clearTimeout(handler); }};
End 事件
到了最后这里我们要处理的就是所有的结束时间,包括 press-end
和 pan-end
。
这两个 end 事件都会在 end 函数中判断所得,如果在用户操作的过程中触发了 pan-start
或者 press-start
事件,到了 end 函数这里,对应的状态就会是 true。
所以我们对 end 函数做了以下改造:
let end = point => { if (isTap) { console.log('tap'); clearTimeout(handler); } if (isPan) { console.log('pan-end'); } if (isPress) { console.log('press-end'); }};
最后我们需要在 cancel 事件触发的时候,清楚掉 press 事件的 setTimeout。既然我们的操作被打断了,那也不可能会触发我们的长按事件了。
// 加入 cancellet cancel = point => { clearTimeout(handler); console.log('cancel');};
我们除了 flick
的逻辑,我们已经完成所有手势库里面的事件了。并且也能正确的区分这几种手势操作了。
以上是“怎么使用JavaScript实现手势库”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!