通過昨天對移動端基礎的瞭解,今天就來用原生JS實現一下咱們的幻燈片。html
由於是用原生實現,因此本文篇幅較長,各位看官只需理解思路便可,代碼部分能夠粗略看看。web
畢竟咱們有better-scroll這樣封裝好的框架能更快速實現效果。b( ̄▽ ̄)d 框架
首先根據咱們昨天的滑屏操做,先將幻燈片的滑屏效果作出來。這裏你們將照片地址更換成本身的就能獲得效果。flex
案例要在客戶端纔有效果哦,若是在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的代碼。紅色的爲添加的新代碼。ui
<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的時候將它清除。spa
咱們實現上面效果後,能夠發現會有劃出去的風險,接下來咱們要實現無縫滾動code
在此以前,咱們要了解實現無縫滾動的原理,下面我作了個圖,一目瞭然,若是有不明白能夠評論聯繫我。orm
原理就是:當用戶往第一組的第一張滑動時,咱們將他移動到第二組的第一張。htm
當用戶網第二組最後一張滑動時,咱們將他移動到第一組的最後一張。
<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>