- 列表一
- 列表二
- 列表三
- 列表四
- 列表五
- 列表六
- 列表七
- 列表八
- 列表九
- 列表十
作者: Levi丶
https://segmentfault.com/a/1190000017852497
什么是 Touch滑动?就是类似于 PC端的滚动事件,但是在移动端是没有滚动事件的,所以就要用到 Touch事件结合 js去实现,效果如下:
什么是移动端的 Touch事件?在移动端 Touch事件可以细分成三种,分别是: touchstart、 touchmove和 touchend,并且 touch事件必须要用 addEventListener去监听。
// 手指触碰到屏幕时触发
element.addEventListener('touchstart', function (e) {
// 打印的事件对象
console.log(e)
})
changedTouches、 targetTouches、 touches都是伪数组,里面装的是手指列表。
其实这三种返回的对象,都是表示用户触摸事件时的手指信息,之所以是一个伪数组,是因为有可能出现多指同时触摸,但是在实际工作中一般不去考虑多指的情况。而它们唯一的区别就是在 touchstart和 touchmove事件的时候, changedTouches、 targetTouches、 touches都能获取到手指的信息,但是在 touchend事件的时候, targetTouches、 touches对象是不能返回离开屏幕时的手指信息,只有 changedTouches对象能返回。
我们可以看下上面的图片,在 changedTouche[0]中,有些值:
clientX:74 // 触摸点相对于浏览器的 viewport 左边缘的 x 坐标,不会包括左边的滚动距离。
clientY:73 // 触摸点相对于浏览器的 viewport 上边缘的 Y 坐标,不会包括上边的滚动距离。
screenX:2202 // 触摸点相对于屏幕左边缘的 x 坐标。
screenY:327 // 触摸点相对于屏幕上边缘的 Y 坐标。
pageX:65 // 触摸点相对于 document 的左边缘的 x 坐标,包括左边的滚动距离
pageY:18 // 触摸点相对于 document 的上边缘的 Y 坐标,包括左边的滚动距离
此案例模拟的是移动端的一种滑动菜单效果。
- 列表一
- 列表二
- 列表三
- 列表四
- 列表五
- 列表六
- 列表七
- 列表八
- 列表九
- 列表十
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
}
.main {
width: 100%;
height: 100%;
}
.draw {
width: 60px;
height: 500px;
border: 2px solid #ccc;
overflow: hidden;
position: fixed;
left: 10px;
top: 50%;
transform: translateY(-50%);
}
li {
display: block;
list-style: none;
width: 60px;
height: 60px;
line-height: 60px;
text-align: center;
}
手指触摸到列表向下滑动的时候,列表应该跟着向下滑动,当手指离开屏幕的时候,列表应该停在滑动的位置。这里就会用到上面准备阶段的知识点了,不明白的可以参考上面的概念。
var draw = document.querySelector('#draw');
var ul = draw.children[0];
// touchstart时,记录手指在Y轴上落点距离可视顶部距离
var startY = 0;
ul.addEventListener('touchstart', function (e) {
startY = e.changedTouches[0].clientY;
});
// touchmove时,记录手指在Y轴上的位置(滚动距离)
ul.addEventListener('touchmove', function (e) {
// 获取差值
var dy = e.changedTouches[0].clientY - startY;
// 设置 ul 在 Y 轴上的偏移
ul.style.transform = 'translateY(' + dy + 'px)';
})
上面的效果图,细心的朋友可能已经发现了问题,在第一次的时候,得到了我们想要的效果,但是在第二次的时候,我们继续向下移动了一段距离,但是 ul并没有接着第一次的位置继续向下,而是瞬间跳了上去。
虽然第二次是继续向下移动了一段距离,但是触摸结束后,最终是将此时的差值,重新赋值给了 ul的 Y轴偏移,所以视觉上“跳了上去”。
每一次滑动结束之后,都应该记录下此次滑动的距离,与之前的进行累加,待下一次滑动的时候,* ul* 在 Y轴的偏移值应该是之前的距离加上本次滑动的距离。
var draw = document.querySelector('#draw');
var ul = draw.children[0];
var startY = 0; // 刚触碰到屏幕的时的手指信息
var centerY = 0; // 用来记录每次触摸时上一次的偏移距离
// touchstart时,记录手指在Y轴上落点距离可视顶部距离
ul.addEventListener('touchstart', function (e) {
startY = e.changedTouches[0].clientY;
})
// touchmove时,记录手指在Y轴上的位置(滚动距离)
ul.addEventListener('touchmove', function (e) {
// 获取差值
var dy = e.changedTouches[0].clientY - startY;
// 上次的滑动距离加上本次的滑动距离
var tempY = centerY + dy;
// 设置 ul 在 Y 轴上的偏移
ul.style.transform = 'translateY(' + tempY + 'px)';
})
到上面一步,我们已经可以实现列表的滑动了,但是也存在一个问题,就是向上或者向下的时候没有限制,上下可以无限的滑动,甚至再用点力,就看不到列表了。为了美观和实用,这样肯定不行的,需要给它设定一个区间,设定向上或者向下最多只能留白多少。
设定向下最大区间的值比较简单,直接设定一个值,当上一次滑动的距离加上本次滑动的距离大于这个值的时候,就不让它再继续往下滑了,让他直接等于这个设定的值。
示例代码:
var maxDown = 50; // 设定一个最大向下滑动的距离
// touchmove 时,记录此时手指在 Y 轴上的落点距离可视顶部距离
ul.addEventListener('touchmove', function(e) {
// 获取差值
var dy = e.changedTouches[0].clientY - startY;
// 上次的滑动距离加上本次的滑动距离
var tempY = centerY + dy;
// 当上次滑动的距离加上本次滑动的距离 大于 设定的最大向下距离的时候
if(tempY > maxDown) {
// 直接让偏移的值 等于这个设定值
tempY = maxDown;
}
// 设置 ul 在 Y 轴上的偏移
ul.style.transform = 'translateY('+ tempY +'px)';
})
向上滑动时,当 ul的底部距盒子底部的距离大于设定值的时候,不让其继续向上滑动,关键是这个值怎么去判断?
求出向上滑动最大值
注意:因为 ul 是向上滑动的,所以求得的距离前面要加上一个负号(-)
示例代码:
var maxDown = 50; // 设定一个最大向下滑动的距离
var maxUp = -(ul.offsetHeight - draw.offsetHeight + maxDown); //最大向上滑动距离
// touchmove 时,记录此时手指在 Y 轴上的落点距离可视顶部距离
ul.addEventListener('touchmove', function(e) {
// 获取差值
var dy = e.changedTouches[0].clientY - startY;
// 上次的滑动距离加上本次的滑动距离
var tempY = centerY + dy;
// 当上次滑动的距离加上本次滑动的距离 大于 设定的最大向下距离的时候
if(tempY > maxDown) {
// 直接让偏移的值 等于这个设定值
tempY = maxDown;
}
// 当上次滑动的距离加上本次滑动的距离 小于 设定的最大向上距离的时候
else if (tempY < maxUp) {
tempY = maxUp;
}
// 设置 ul 在 Y 轴上的偏移
ul.style.transform = 'translateY('+ tempY +'px)';
})
认真观察上图,虽然成功的设置了最大滑动区间,但是你有没有发现,一直往一个方向滑动的时候,虽然列表不会继续往下滑动,但是接着往相反方向滑动的时候,感觉列表滑不动,需要滑一段距离后,列表才会跟着走,这是为什么呢?因为滑动的过程 centerY是一直变的,列表虽然视觉上不动了,但是在 touchend事件的时候,它的 centerY值一直在累加。解决方法请往下看。
“滑动反弹”,这里的反弹是本篇文章的最后一步,上面说到的问题,就在这里解决。因为每一次触发 touchend事件的时候, centerY值就累加一次,所以需要在 touchend事件里做判断。我们设定一个反弹区间,就是当 centerY的值大于或者小于某个值的时候,让它触发反弹。
向上的值比较简单,设置成“ 0 ”。为什么是“ 0 ”呢?我们限定只要手指离开时,上一次的滑动距离加上本次的距离 >0 的时候,就让它触发反弹,并且反弹回 0 点的位置,也就是两次滑动的距离和 =0。
var maxUpBounce = 0; //向上反弹阈值
// touchend时,记录当前滚动距离
ul.addEventListener('touchend', function (e) {
// 获取差值
var dy = e.changedTouches[0].clientY - startY;
// 记录移动的距离
centerY = centerY + dy;
// 两次滑动的距离 大于 设定的 向上 反弹值时
if (centerY > maxUpBounce) {
// 让两次滑动的距离 等于 设置的值
centerY = maxUpBounce;
// 添加过渡
ul.style.transition = 'transform .5s';
ul.style.transform = 'translateY(' + centerY + 'px)';
}
})
向下的值其实跟之前求滑动区间差不多,我们参考下图,当列表向上滑动,滑动到列表底部的时候,只要此时再向上滑动,就让它向下反弹。向下反弹值就是 -(ul.offsetHeight-draw.offsetHeight),只要滑动的差值小于这个设定值,就让它向下反弹,并且反弹回设定值的位置。
var maxUpBounce = 0; //向上反弹阈值
var maxDownBounce = -(ul.offsetHeight - draw.offsetHeight); // 向下反弹阈值
// touchend时,记录当前滚动距离
ul.addEventListener('touchend', function (e) {
// 获取差值
var dy = e.changedTouches[0].clientY - startY;
// 记录移动的距离
centerY = centerY + dy;
// 两次滑动的距离 大于 设定的 向上 反弹值时
if (centerY > maxUpBounce) {
// 让两次滑动的距离 等于 设置的值
centerY = maxUpBounce;
// 添加过渡
ul.style.transition = 'transform .5s';
ul.style.transform = 'translateY(' + centerY + 'px)';
}
// 两次滑动的距离 小于 设定的 向下 反弹值时
else if (centerY < maxDownBounce) {
// 让两次滑动的距离 等于 设置的值
centerY = maxDownBounce;
// 添加过渡
ul.style.transition = 'transform .5s';
ul.style.transform = 'translateY(' + centerY + 'px)'
}
})
注意:在 touchend事件的时候,给列表添加了 transition属性才会有反弹的效果,但是,下一次滑动的时候, touchmove事件的时候,这个属性还存在,所以就会出现滑动的时候有顿挫感,所以在 touchmove事件的时候,一进来就清一下过渡 ul.style.transition=‘none’;。
mobile-touch
- 列表一
- 列表二
- 列表三
- 列表四
- 列表五
- 列表六
- 列表七
- 列表八
- 列表九
- 列表十
(≥3≤)/