倪彼情感
您的当前位置:首页原生js实现移动端Touch滑动反弹的方法(代码示例)

原生js实现移动端Touch滑动反弹的方法(代码示例)

来源:倪彼情感


示例代码:

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值一直在累加。解决方法请往下看:

6. 设定反弹区间

“滑动反弹”,这里的反弹是本篇文章的最后一步,上面说到的问题,就在这里解决。因为每一次触发touchend事件的时候,centerY值就累加一次,所以需要在touchend事件里做判断。我们设定一个反弹区间,就是当centerY的值大于或者小于某个值的时候,让它触发反弹。

设定向上反弹值:

向上的值比较简单,设置成“0”。为什么是“0”呢?我们限定只要手指离开时,上一次的滑动距离加上本次的距离> 0的时候,就让它触发反弹,并且反弹回0点的位置,也就是两次滑动的距离和= 0

示例代码:

// 向上反弹
var maxUpBounce = 0;

// touchend 时,记录此时手指在 Y 轴上的落点距离可视顶部距离
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 时,记录此时手指在 Y 轴上的落点距离可视顶部距离
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';

完成后效果图:

7. 完整代码

<!DOCTYPE html>
<html>

<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <title>移动端 Touch 滑动反弹</title>
 <style>
 /* 样式初始化 */
 * {
 margin: 0;
 padding: 0;
 }

 html,
 body {
 width: 100%;

 }

 aside {
 height: 100%;
 width: 100%;
 }

 /* 列表的父盒子,宽高 */
 /* 注意设置overflow: hidden;样式后,超出这个盒子的ul将不会显示 */
 .draw {
 width: 60px;
 height: 500px;
 border: 2px solid #ccc;
 overflow: hidden;
 position: fixed;
 left: 10px;
 top: 50%;
 transform: translateY(-50%);
 }

 /* li 设置了浮动, 所以 ul 要清除浮动 */
 ul:after {
 content: "";
 display: block;
 visibility: hidden;
 height: 0;
 clear: both;
 }

 ul {
 zoom: 1;
 }

 li {
 list-style: none;
 float: left;
 width: 60px;
 height: 60px;
 line-height: 60px;
 text-align: center;
 }
 </style>
</head>
<aside>
 <div id="draw">
 <ul>
 <li style="background:orange">列表一</li>
 <li style="background:yellowgreen">列表二</li>
 <li style="background:yellow">列表三</li>
 <li style="background:cyan">列表四</li>
 <li style="background:orangered">列表五</li>
 <li style="background:pink">列表六</li>
 <li style="background:red">列表七</li>
 <li style="background:purple">列表八</li>
 <li style="background:violet">列表九</li>
 <li style="background:brown">列表十</li>
 </ul>
 </div>
</aside>

<body>
 <script>
 var draw = document.querySelector('#draw');
 var ul = draw.children[0];

 var startY = 0; // 刚触碰到屏幕的时的手指信息
 var centerY = 0; // 用来记录每次触摸时上一次的偏移距离
 var maxDown = 50; // 设定一个最大向下滑动的距离
 var maxUp = -(ul.offsetHeight - draw.offsetHeight + maxDown); // 求得一个最大向上滑动的距离
 var maxUpBounce = 0; // 向上反弹值
 var maxDownBounce = -(ul.offsetHeight - draw.offsetHeight); // 向下反弹值

 // touchstart 时,记录手指在 Y 轴上的落点距离可视顶部距离
 ul.addEventListener('touchstart', function (e) {
 startY = e.changedTouches[0].clientY;
 })

 // touchmove 时,记录此时手指在 Y 轴上的落点距离可视顶部距离
 ul.addEventListener('touchmove', function (e) {
 // 清除过渡
 ul.style.transition = 'none';
 // 获取差值
 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)';
 })

 // touchend 时,记录此时手指在 Y 轴上的落点距离可视顶部距离
 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)';
 }
 })
 </script>
</body>

</html>
显示全文