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

来源: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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...