移動端事件——移動端滑屏切換的幻燈片(二)

来源:https://www.cnblogs.com/jfen625/archive/2020/03/21/12543333.html
-Advertisement-
Play Games

經過昨天對移動端基礎的瞭解,今天就來用原生JS實現一下我們的幻燈片。 因為是用原生實現,所以本文篇幅較長,各位看官只需理解思路即可,代碼部分可以粗略看看。 畢竟我們有better-scroll這樣封裝好的框架能更快速實現效果。b( ̄▽ ̄)d 首先根據我們昨天的滑屏操作,先將幻燈片的滑屏效果做出來。這 ...


經過昨天對移動端基礎的瞭解,今天就來用原生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;
            width: 100vw;
            overflow: hidden;
        }
        #list {
            float: left;
            display: flex;
            display: -webkit-box;
        }
        #list li {
            flex: none;
            width: 100vw;
        }
        #list img {
            width: 100%;
            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;  
        }
    </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;
            width: 100vw;
            overflow: hidden;
        }
        #list {
            float: left;
            display: flex;
            display: -webkit-box;
        }
        #list li {
            flex: none;
            width: 100vw;
        }
        #list img {
            width: 100%;
            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="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>\u8FD9\u662F\u7B2C" + 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>

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • @ "TOC" 方法一 此方法使用用到了數組操作的sort和push方法,但缺點是在數組對象很多的時候,就會不知道數組對象的最後一位是多少。 方法二 此方法用到了Math函數,解決了上面方法的不足之處。 歡迎大家評論補充 ...
  • txt文本 js html 以上內容借鑒 "https://blog.csdn.net/qq_20916285/article/details/46695839" 。 ...
  • Vue是MVVM設計模式的前端框架,其實現Todolist相比於通過Jquery操作Dom來實現的方法是非常簡潔的。下麵我就來對比下這兩種方法。 Vue實現 可以看到,vue實現todolist僅僅是對Model層進行的操作,既對數據進行操作,在操作完成後,vue內置的ViewModel層會自動對數 ...
  • ```js 點擊 ``` ...
  • 1、求出1 2018中所有含8的數字,使用數組的reduce、map、filter方法,如1 10中:8;1 20中:8,18; 最後拼湊著使用了三個方法,完成了這個題目,不知道題目我是不是沒理解清楚,是必須用到這三個函數還是只用其中之一就可,如果只用reduce,也可以實現,如下 2、解析url中 ...
  • 如下代碼 2、回調函數 3、async await ...
  • 產生原因 如果從後端返回過來的數組數據,進行遍歷的時候不在success回調函數內,則會產生如下的數據格式,雖然其也是數組格式,但是內部的值取不出來,給後臺也傳不過去。 原因:其實跟__ob__: Observer這個屬性沒有多少關係,原因還是在於非同步,因為wx.chooseImage是一個非同步執行 ...
  • 1、數組扁平化(數組降維) 數組扁平化是指將一個多維數組變為一維數組 [1, [2, 3, [4, 5]]] > [1, 2, 3, 4, 5] 2、給定一個數組,將數組中的所有0移動到末尾,並保持非0元素的順序不改變。如 [0,1,0,3,12] 移動後的期望數組為 [1,3,12,0,0] 要求 ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...