解决移动端滑动事件冲突【有左右滑动轮播图,又有上下滑动滚动条,斜滑时会相互影响】

前言

在移动端中,当我们的页面既有上下滑动又有左右滑动时,比如我们顶部有轮播图(左右移动),页面还包含上下移动滚动条。当我们斜滑页面,页面也会斜着运动,即触发了左右移动事件又触发了上下移动事件。布局还可能会错乱,这不是我们想要的,我们只想它左右或者上下滑动,不同时滑动。接下来我们来解决这个问题

一、touch触摸事件介绍

  • touchstart:当手指触摸屏幕时候触发,即使已经有一个手指放在屏幕上也会触发
  • touchmove:当手指在屏幕上滑动的时候连续地触发。在这个事件发生期间,调用preventDefault()事件可以阻止默认事件
  • touchend:当手指从屏幕上离开的时候触发
  • touchcancel:当系统停止跟踪触摸的时候触发。关于这个事件的确切出发时间,文档中并没有具体说明,咱们只能去猜测了

二、TouchEvent 对象

每一个touch事件的触发都会产生一个TouchEvent对象,以下是TouchEvent对象三个比较常用的重要属性

  • touches:当前位于屏幕上的所有手指的列表
  • targetTouches:位于当前DOM元素上手指的列表
  • changedTouches:涉及当前事件手指的列表
 wrap.addEventListener("touchstart", (e) => {
    console.log(e)
 })

三、touchEvent 对象属性

每个Touch对象包含以下属性

  • clientX:触摸目标在视口中的x坐标
  • clientY:触摸目标在视口中的y坐标
  • identifier:标识触摸的唯一ID
  • pageX:触摸目标在页面中的x坐标
  • pageY:触摸目标在页面中的y坐标
  • screenX:触摸目标在屏幕中的x坐标
  • screenY:触摸目标在屏幕中的y坐标
  • target:触目的DOM节点目标

四、js解决移动端滑动问题(幻灯片案例)

解决思路:监听滑动,预判用户是左右滑动,还是上下滑动,如果水平移动距离 > 垂直移动距离 就是做水平滑动,反之就是垂直滑动,再通过阻止默认事件来解决滑动问题

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    html {
      font-size: 10vw;
    }

    body {
      margin: 0;
    }

    ul {
      margin: 0;
      padding: 0;
      list-style: none;
    }

    #wrap {
      position: relative;
      width: 100vw;
      overflow: hidden;
    }

    #list {
      float: left;
      display: flex;
      display: -webkit-box;
    }

    #list li {
      flex: none;
      width: 100vw;
    }

    #list img {
      width: 100%;
      height: 200px;
      display: block;
    }

    .nav {
      position: absolute;
      left: 0;
      bottom: .2rem;
      width: 100%;
      text-align: center;
      vertical-align: top;
    }

    .nav a {
      display: inline-block;
      width: .3rem;
      height: .3rem;
      background: #fff;
      margin: 0 .1rem;
      border-radius: .15rem;
      transition: .3s;
    }

    .nav .active {
      width: .6rem;
      color: #fff;
    }

    .textList {
      margin: 0;
      padding: 0;
      list-style: none;
    }

    .textList li {
      font: 14px/40px "宋体";
      padding-left: 20px;
      border-bottom: 1px solid #000;
    }
  </style>
</head>

<body>
  <div id="wrap">

    <!-- 幻灯片 -->
    <ul id="list">
      <li><img src="https://i02piccdn.sogoucdn.com/f8773bf41fc728d8" alt=""></li>
      <li><img src="https://i02piccdn.sogoucdn.com/03469eff264233a8" alt=""></li>
      <li><img src="https://i02piccdn.sogoucdn.com/b8322a9d8751fd62" alt=""></li>
      <li><img src="https://i04piccdn.sogoucdn.com/87a97031f6954b64" alt=""></li>
      <li><img src="https://i03piccdn.sogoucdn.com/d1eef212d4b16e56" alt=""></li>
    </ul>

    <!-- 点 -->
    <nav class="nav">
      <a class="active"></a>
      <a></a>
      <a></a>
      <a></a>
      <a></a>
    </nav>

  </div>

  <!-- 测试数据列表 -->
  <ul class="textList"></ul>

  <script>
    // 生成两百行测试数据列表
    {
      let list = document.querySelector(".textList");
      list.innerHTML = [...(".".repeat(200))].map((item, index) => {
        return `<li>这是第${index}行测试数据</li>`;
      }).join("");
    }


    // 幻灯片 
    /*
        在两个方向的滑动上,如果有一些不同的操作,这里要注意我们要进行方向判断
        每次滑动时判断方向,一旦判明方向,就不在判断
    */
    {
      let wrap = document.querySelector("#wrap");
      let list = document.querySelector("#list");
      let navs = document.querySelectorAll(".nav a");
      let startPoint = {}; 
      let translateX = 0;
      let startTranslateX = 0;
      let now = 0;
      let wrapW = wrap.clientWidth;
      const range = .3 * wrapW;
      let isFirst = true;
      let isMove = true;
      list.innerHTML += list.innerHTML;

      // 当手指触摸屏幕时触发
      wrap.addEventListener("touchstart", (e) => {
        let touch = e.changedTouches[0];
        list.style.transition = "none";
        startPoint = {
          x: touch.pageX,
          y: touch.pageY
        };
        if (now == 0) {
          now = navs.length;
        } else if (now == navs.length * 2 - 1) {
          now = navs.length - 1;
        }
        translateX = -now * wrapW;
        list.style.transform = `translateX(${translateX}px)`;
        startTranslateX = translateX;
        isFirst = true;
        isMove = true;
      });
      
      // 当手指在屏幕上滑动时连续地触发
      wrap.addEventListener("touchmove", (e) => {
        let touch = e.changedTouches[0];
        let nowPoint = {
          x: touch.pageX,
          y: touch.pageY
        };
        let dis = {
          x: nowPoint.x - startPoint.x,
          y: nowPoint.y - startPoint.y
        };
        // 在安卓下,手指按下时,如果触摸面积比较大,容易误触 touchmove
        if (isFirst) {
          if (Math.abs(dis.x) - Math.abs(dis.y) > 5) {
            // 左右滑动, 阻止滚动条不进行上下滑动,而让幻灯片滑动
            isMove = true;
            isFirst = false;
          } else if (Math.abs(dis.y) - Math.abs(dis.x) > 5) {
            // 上下滑动, 不阻止滚动条滑动,禁止幻灯片滑动
            isMove = false;
            isFirst = false;
          }
        }
        if (isMove) {
          e.preventDefault();
          if (!isFirst) {
            translateX = startTranslateX + dis.x;
            list.style.transform = `translateX(${translateX}px)`;
          }
        }
      });
      
      // 当手指从屏幕上离开时触发
      wrap.addEventListener("touchend", (e) => {
        let touch = e.changedTouches[0];
        let nowPoint = {
          x: touch.pageX,
          y: touch.pageY
        };
        let dis = {
          x: nowPoint.x - startPoint.x,
          y: nowPoint.y - startPoint.y
        };
        
        if (Math.abs(dis.x) > range && isMove) {
          now -= dis.x / Math.abs(dis.x);
        }

        navs.forEach(item => {
          item.classList.remove("active")
        });
        translateX = -now * wrapW;
        list.style.transition = ".3s";
        list.style.transform = `translateX(${translateX}px)`;
        navs[now % navs.length].classList.add("active");
      });
    }    
  </script>
</body>

</html>

五、效果图

六、移动端滚动插件

Swiper: https://github.com/nolimits4web/Swiper

better-scroll: https://ustbhuangyi.github.io/better-scroll/#/zh

文章每周持续更新,可以微信搜索「 前端大集锦 」第一时间阅读,回复【视频】【书籍】领取200G视频资料和30本PDF书籍资料

扫描二维码关注公众号,回复: 12874068 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_38128179/article/details/114287812
今日推荐