• 移动端事件(二)——移动端滑屏切换的幻灯片


    经过昨天对移动端基础的了解,今天就来用原生JS实现一下我们的幻灯片。

    因为是用原生实现,所以本文篇幅较长,各位看官只需理解思路即可,代码部分可以粗略看看。

    毕竟我们有better-scroll这样封装好的框架能更快速实现效果。b( ̄▽ ̄)d 

    首先根据我们昨天的滑屏操作,先将幻灯片的滑屏效果做出来。这里大家将照片地址更换成自己的就能得到效果。

    案例要在客户端才有效果哦,如果在PC端,网页中右键点审查,控制器旁边有个手机图标,点击下图这个也能有效果。

    <!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;
                 100vw;
                overflow: hidden;
            }
            #list {
                float: left;
                display: flex;
                display: -webkit-box;
            }
            #list li {
                flex: none;
                 100vw;
            }
            #list img {
                 100%;
                display: block;
            }
            .nav {
                position: absolute;
                left: 0;
                bottom: .2rem;
                 100%;
                text-align: center;
                vertical-align: top;
            }
            .nav a {
                display: inline-block;
                 .3rem;
                height: .3rem;
                background: #fff;
                margin: 0 .1rem;
                border-radius: .15rem;
                transition: .3s;
            }
            .nav .active {
                 .6rem;  
                color: #fff;  
            }
        </style>
    </head>
    <body>  
    <div id="wrap">
        <ul id="list">
            <li><img src="img/banner01.png" /></li>
            <li><img src="img/banner02.png" /></li>
            <li><img src="img/banner03.png" /></li>
            <li><img src="img/banner04.png" /></li>
        </ul>
        <nav class="nav">
            <a class="active"></a><a></a><a></a><a></a>
        </nav>
    </div>  
    <script>
     // 幻灯片效果   
    {
        let wrap = document.querySelector("#wrap");
        let list = document.querySelector("#list");
        let navs = document.querySelectorAll(".nav a");
        let translateX = 0; //元素的移动位置
        let startPoint = {}; //摁下时手指坐标
        let disPoint = {};//手指移动距离
        let startX = 0;//摁下时元素坐标
    
        wrap.addEventListener("touchstart",({changedTouches})=>{
            startPoint = {
                x: changedTouches[0].pageX,
                y: changedTouches[0].pageY
            };
            startX = translateX;
        });
        wrap.addEventListener("touchmove",(e)=>{
            let touch = e.changedTouches[0];
            let nowPoint = {
                x: touch.pageX,
                y: touch.pageY
            };
            disPoint = {
                x: nowPoint.x - startPoint.x,
                y: nowPoint.y - startPoint.y
            };
            translateX = disPoint.x + startX;
            list.style.transform = `translateX(${translateX}px)`;
        });
    }   
    </script>
    </body>
    </html>

    滑屏效果做出来以后,我们给它添加动画,接下来为了大家方便看,就只写JavaScript的代码。红色的为添加的新代码。

    <script>
     // 幻灯片效果   
    {
        let wrap = document.querySelector("#wrap");
        let list = document.querySelector("#list");
        let navs = document.querySelectorAll(".nav a");
        let translateX = 0; //元素的移动位置
        let startPoint = {}; //摁下时手指坐标
        let startX = 0;//摁下时元素坐标
        let disPoint = {};//手指移动距离
        let now = 0; // 记录当前在第几张
        const Range = .3* wrap.clientWidth; // 移动超过屏幕 30% 时,抬起切换到下一张
    
        wrap.addEventListener("touchstart",({changedTouches})=>{
            list.style.transition = "none";
            startPoint = {
                x: changedTouches[0].pageX,
                y: changedTouches[0].pageY
            };
            startX = translateX;
            
        });
        wrap.addEventListener("touchmove",(e)=>{
            let touch = e.changedTouches[0];
            let nowPoint = {
                x: touch.pageX,
                y: touch.pageY
            };
            disPoint = {
                x: nowPoint.x - startPoint.x,
                y: nowPoint.y - startPoint.y
            };
            translateX = disPoint.x + startX;
            list.style.transform = `translateX(${translateX}px)`;
        });
        wrap.addEventListener("touchend",()=>{
            if(Math.abs(disPoint.x)>Range){ //切换到下一张
                //console.log(disPoint.x/Math.abs(disPoint.x));
                now -= disPoint.x/Math.abs(disPoint.x);
                // 求当前要看第几张
            }
            translateX = -now*wrap.clientWidth;
            list.style.transition = ".3s";
            list.style.transform = `translateX(${translateX}px)`;
            //console.log(now);
        });
    }   
    </script>

    这一步我们将每次手指离开屏幕后进行判断,判断手指移动的距离是否超过30%,抬起则切换到下一张。我们在每次切换时添加了0.3s的延迟动画。因为这延迟动画在手指触屏时就会生效,所以我们在touchstart的时候将它清除。

    我们实现上面效果后,可以发现会有划出去的风险,接下来我们要实现无缝滚动

    在此之前,我们要了解实现无缝滚动的原理,下面我做了个图,一目了然,如果有不明白可以评论联系我。

     原理就是:当用户往第一组的第一张滑动时,我们将他移动到第二组的第一张。

          当用户网第二组最后一张滑动时,我们将他移动到第一组的最后一张。

    <script>
     // 幻灯片效果   
    {
        let wrap = document.querySelector("#wrap");
        let list = document.querySelector("#list");
        let navs = document.querySelectorAll(".nav a");
        let translateX = 0; //元素的移动位置
        let startPoint = {}; //摁下时手指坐标
        let startX = 0;//摁下时元素坐标
        let disPoint = {};//手指移动距离
        let now = 0; // 记录当前在第几张
        const Range = .3* wrap.clientWidth; // 移动超过屏幕 30% 时,抬起切换到下一张
        list.innerHTML += list.innerHTML; // 把 list 图片复制一份
        wrap.addEventListener("touchstart",({changedTouches})=>{
            list.style.transition = "none";
            startPoint = {
                x: changedTouches[0].pageX,
                y: changedTouches[0].pageY
            };
            if(now === 0){
                now = navs.length;
            } else if(now === navs.length*2-1){
                now = navs.length - 1;
            }
            translateX = -now*wrap.clientWidth;
            list.style.transform = `translateX(${translateX}px)`;
            startX = translateX;
            
        });
        wrap.addEventListener("touchmove",(e)=>{
            let touch = e.changedTouches[0];
            let nowPoint = {
                x: touch.pageX,
                y: touch.pageY
            };
            disPoint = {
                x: nowPoint.x - startPoint.x,
                y: nowPoint.y - startPoint.y
            };
            translateX = disPoint.x + startX;
            list.style.transform = `translateX(${translateX}px)`;
        });
        wrap.addEventListener("touchend",()=>{
            if(Math.abs(disPoint.x)>Range){ //切换到下一张
                //console.log(disPoint.x/Math.abs(disPoint.x));
                now -= disPoint.x/Math.abs(disPoint.x);
                // 求当前要看第几张
            }
            translateX = -now*wrap.clientWidth;
            list.style.transition = ".3s";
            list.style.transform = `translateX(${translateX}px)`;
        });
    }   

    实现这一效果,首先我们将图片复制多一份,然后在手指点击屏幕时,

      判断现在是否是第一组的第一张,是则跳转到第第二组的第一张

      或者是否为第二组的最后一张,是则跳转到第一组的最后一张。

        对其style里的translateX进行进行更改就能实现无缝滚动。

    接着我们对下面的白点进行同步,只用在touchend下添加以下代码即可

    // 同步 nav
    navs.forEach(item=>{
          item.classList.remove("active");
    });
    navs[now%navs.length].classList.add("active");

    至此我们已经完成一个比较简单的移动端轮播。

    但是

    我们还有bug,就是当用户斜向上滑动时,轮播与下面内容皆会滑动。

    因此我们需要做:

    1. 判断用户想要滑动的是幻灯片,还是想要滚动滚动条
    2. 如果想要滑动幻灯片,就阻止滚动条
    3. 如果想要滚动滚动条,就阻止幻灯片
    4. 注意 一旦在滑动的过程中判断到用户的滑动方向之后,就不在做方向修改

    以下便是所有效果

    <!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;
                 100vw;
                overflow: hidden;
            }
            #list {
                float: left;
                display: flex;
                display: -webkit-box;
            }
            #list li {
                flex: none;
                 100vw;
            }
            #list img {
                 100%;
                display: block;
            }
            .nav {
                position: absolute;
                left: 0;
                bottom: .2rem;
                 100%;
                text-align: center;
                vertical-align: top;
            }
            .nav a {
                display: inline-block;
                 .3rem;
                height: .3rem;
                background: #fff;
                margin: 0 .1rem;
                border-radius: .15rem;
                transition: .3s;
            }
            .nav .active {
                 .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="img/banner01.png" /></li>
            <li><img src="img/banner02.png" /></li>
            <li><img src="img/banner03.png" /></li>
            <li><img src="img/banner04.png" /></li>
        </ul>
        <nav class="nav">
            <a class="active"></a><a></a><a></a><a></a>
        </nav>
    </div>  
    <ul class="textList">
    
    </ul>
    <script>
    "use strict";
    
    // 补充列表内容
    {
      var txtList = document.querySelector(".textList");
      txtList.innerHTML = [...(".".repeat(100))].map(function (item, index) {
        return "<li>u8FD9u662Fu7B2C" + index + "u4E2Ali</li>";
      }).join("");
    } // 幻灯片
    
    /*
        判断用户滑动方向时:
            一旦判断到用户的滑动方向,就认定该次操作用户想要进行上下或左右滑动,中间不再修改,一直到用户下一次再执行 start
    */
    
    {
      var wrap = document.querySelector("#wrap");
      var list = document.querySelector("#list");
      list.innerHTML += list.innerHTML; // 把图片复制一份用来处理无缝
    
      var startPoint = {}; // 摁下时手指位置
    
      var startX = 0; // 摁下时元素的位置
    
      var translateX = 0; // 元素的 tranlateX 值
    
      var now = 0; //记录当前在第几张
    
      var navs = document.querySelectorAll(".nav a");
      var RANGE = wrap.clientWidth * .3; //超过该幅度切换上一张下一张
    
      var isMove = false; // 是否需要滑动幻灯片
    
      var isDir = true; // 记录是否已经判断到了方向 true 还没有判断到方向,false已经判断到了方向
    
      wrap.addEventListener("touchstart", function (_ref) {
        var changedTouches = _ref.changedTouches;
        list.style.transition = "none";
        var touch = changedTouches[0];
        startPoint = {
          x: touch.pageX,
          y: touch.pageY
        };
    
        if (now == 0) {
          //第1组第0张会有划出去的风险
          now = navs.length;
        } else if (now == navs.length * 2 - 1) {
          // 第2组最后一张,有划出去的风险
          now = navs.length - 1;
        }
    
        translateX = -now * wrap.clientWidth;
        list.style.WebkitTransform = list.style.transform = "translateX(" + translateX + "px)";
        startX = translateX;
        isMove = false;
        isDir = true;
      });
      wrap.addEventListener("touchmove", function (e) {
        var touch = e.changedTouches[0];
        var nowPoint = {
          x: touch.pageX,
          y: touch.pageY
        };
        var dis = {
          x: nowPoint.x - startPoint.x,
          y: nowPoint.y - startPoint.y
        }; // 判断方向根据需求来阻止默认事件
    
        if (isDir) {
          if (Math.abs(dis.x) - Math.abs(dis.y) > 5) {
            // 左右滑动
            isMove = true;
            isDir = false;
          } else if (Math.abs(dis.y) - Math.abs(dis.x) > 5) {
            // 上下滑动
            isMove = false;
            isDir = false;
          }
    
          e.preventDefault();
        }
    
        console.log(isMove, isDir);
    
        if (isMove) {
          translateX = startX + dis.x;
          list.style.WebkitTransform = list.style.transform = "translateX(" + translateX + "px)";
          e.preventDefault();
        }
      });
      wrap.addEventListener("touchend", function (_ref2) {
        var changedTouches = _ref2.changedTouches;
        var touch = changedTouches[0];
        var nowPoint = {
          x: touch.pageX,
          y: touch.pageY
        };
        var dis = {
          x: nowPoint.x - startPoint.x,
          y: nowPoint.y - startPoint.y
        }; // 当移动的距离超过图片宽度的 30% 时 切换至下一张或上一张,否则回到当前张
    
        if (Math.abs(dis.x) >= RANGE && isMove) {
          // 切换上一张下一张
          //console.log(dis.x,dis.x/Math.abs(dis.x));
          now -= dis.x / Math.abs(dis.x);
        } //console.log(-now*wrap.clientWidth);
    
    
        translateX = -now * wrap.clientWidth;
        list.style.transition = ".3s";
        list.style.WebkitTransform = list.style.transform = "translateX(" + translateX + "px)";
        navs.forEach(function (nav) {
          nav.classList.remove("active");
        });
        navs[now % navs.length].classList.add("active");
      });
    }
    </script>
    
    </body>
    </html>
  • 相关阅读:
    2013国内IT行业薪资对照表【技术岗位】
    Eclipse查看子类
    whereis 查找命令全路径
    开张了
    Ruby1.8中单行字符串写在多行
    FEMTO是什么
    FUSE文件系统
    魔兽私服pvpgn搭建
    linux网络源码分析(1)
    freehosting申请空间和ssh D设置
  • 原文地址:https://www.cnblogs.com/jfen625/p/12543333.html
Copyright © 2020-2023  润新知