原生 js 完成挪动端 Touch 滑动反弹

《原生 js 完成挪动端 Touch 滑动反弹》

挪动端 Touch 滑动反弹

什么是
Touch滑动?就是类似于
PC端的转动事宜,然则在挪动端是没有转动事宜的,所以就要用到
Touch事宜连系
js去完成,结果以下:

《原生 js 完成挪动端 Touch 滑动反弹》

1. 预备工作

什么是挪动端的
Touch事宜?在挪动端
Touch事宜能够细分红三种,分别是:
touchstart
touchmove
touchend,而且
touch事宜必须要用
addEventListener去监听。

  • touchStart当手指触遇到屏幕的时刻触发
  • touchmove当手指在屏幕上不停挪动的时刻触发
  • touchend当手指脱离屏幕的时刻触发

Touch 事宜触发的 Event 对象:

// 手指触遇到屏幕时触发
element.addEventListener('touchstart', function (e) {
    // 打印的事宜对象
    console.log(e);
})

《原生 js 完成挪动端 Touch 滑动反弹》

changedTouchestargetTouchestouches都是伪数组,内里装的是手指列表

三种返回对象的区分:

实在这三种返回的对象,都是示意用户触摸事宜时的手指信息,之所以是一个伪数组,是由于有能够涌现多指同时触摸,然则在现实工作中平常不去斟酌多指的状况。而它们唯一的区分就是在
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 坐标,包含左侧的转动间隔

2. 基础构造

此案例模仿的是挪动端的一种滑动菜单结果。

HTML部份:

<aside class="main">
  <div class="draw" 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>

css部份:

在列表的父盒子上设定一个
overflow: hidden属性,使超越盒子部份的列表临时隐蔽掉,背面会经由历程
js去完成滑动。

/* 款式初始化 */
* {
  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;
}

结果图:

《原生 js 完成挪动端 Touch 滑动反弹》

3. 初次滑动

手指触摸到列表向下滑动的时刻,列表应当随着向下滑动,当手指脱离屏幕的时刻,列表应当停在滑动的位置。这里就会用到上面预备阶段的学问点了,不明白的能够参考上面的观点。

完成道理:

  • 1、touchstart的时刻,猎取手指触摸的落点A,经由历程这个点对象内里的clientY属性,猎取间隔顶部可视区的间隔;
  • 2、touchmove的时刻,猎取手指的点B,一样的猎取挪动时间隔顶部可视区的间隔;
  • 3、touchmove的时刻,还要做另一件事变,就是猎取两点的差值(B.clientY-A.clientY),将这个差值动态赋值给ulul只须要设置向Y轴方向偏移这个间隔,就可以完成列表随手指滑动

先来张示意图,怎样经由历程 js 让列表滑动起来:

《原生 js 完成挪动端 Touch 滑动反弹》

示例代码:

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)';
})

结果图:

《原生 js 完成挪动端 Touch 滑动反弹》

4. 再次滑动

上面的结果图,仔细的朋侪能够已发明了题目,在第一次的时刻,得到了我们想要的结果,然则在第二次的时刻,我们继承向下挪动了一段间隔,然则
ul并没有接着第一次的位置继承向下,而是霎时跳了上去。

题目剖析:

虽然第二次是继承向下挪动了一段间隔,然则触摸完毕后,最终是将此时的差值,从新赋值给了
ul
Y轴偏移,所以视觉上“跳了上去”。

《原生 js 完成挪动端 Touch 滑动反弹》

处理方法:

每一次滑动完毕以后,都应当纪录下此次滑动的间隔,与之前的举行累加,待下一次滑动的时刻,
ul
Y轴的偏移值应当是之前的间隔加上本次滑动的间隔。

  • 新增touchend事宜,在该事宜里一样的能够猎取到本次滑动的间隔,将它与上一次的间隔相加,赋值给一个全局变量;
  • touchmove事宜里有点小修改,就是在给ul设置偏移值的时刻,除了本次滑动的差值还要加上这个上一次的值;

示意图:

《原生 js 完成挪动端 Touch 滑动反弹》

示例代码:

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)';
})

// touchend 时,纪录此时手指在 Y 轴上的落点间隔可视顶部间隔
ul.addEventListener('touchend', function (e) {
  // 猎取差值
  var dy = e.changedTouches[0].clientY - startY;
  // 纪录挪动的间隔
  centerY = centerY + dy;
})

结果图:

《原生 js 完成挪动端 Touch 滑动反弹》

5. 限制滑动区间

到上面一步,我们已能够完成列表的滑动了,然则也存在一个题目,就是向上或许向下的时刻没有限制,高低能够无穷的滑动,以至再用点力,就看不到列表了。为了雅观和有用,如许一定不可的,须要给它设定一个区间,设定向上或许向下最多只能留白若干。

《原生 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的底部距盒子底部的间隔大于设定值的时刻,不让其继承向上滑动,关键是这个值怎样去推断?

《原生 js 完成挪动端 Touch 滑动反弹》

求出向上滑动最大值:

《原生 js 完成挪动端 Touch 滑动反弹》

注重:由于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)';
})

结果图:

《原生 js 完成挪动端 Touch 滑动反弹》

仔细视察上图,虽然胜利的设置了最大滑动区间,然则你有无发明,一向往一个方向滑动的时刻,虽然列表不会继承往下滑动,然则接着往相反方向滑动的时刻,觉得列表滑不动,须要滑一段间隔后,列表才会随着走,这是为何呢?由于滑动的历程centerY是一向变的,列表虽然视觉上不动了,然则在touchend事宜的时刻,它的centerY值一向在累加。处理方法请往下看:

6. 设定反弹区间

“滑动反弹”,这里的反弹是本篇文章的末了一步,上面说到的题目,就在这里处理。由于每一次触发
touchend事宜的时刻,
centerY值就累加一次,所以须要在
touchend事宜里做推断。我们设定一个反弹区间,就是当
centerY的值大于或许小于某个值的时刻,让它触发反弹。

设定向上反弹值:

向上的值比较简单,设置成“
0”。为何是“
0”呢?我们限制只需手指脱离时,上一次的滑动间隔加上本次的间隔
> 0的时刻,就让它触发反弹,而且反弹回
0点的位置,也就是两次滑动的间隔和
= 0

《原生 js 完成挪动端 Touch 滑动反弹》

示例代码:

// 向上反弹
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),只需滑动的差值小于这个设定值,就让它向下反弹,而且反弹回设定值的位置。

《原生 js 完成挪动端 Touch 滑动反弹》

示例代码:

// 向上反弹值
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';

完成后结果图:

《原生 js 完成挪动端 Touch 滑动反弹》

7. 完全代码

<!DOCTYPE html>
<html lang="en">

<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 class="main">
  <div class="draw" 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>
    原文作者:Levi丶
    原文地址: https://segmentfault.com/a/1190000017852497
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞