移動端輪播圖功能和PC端基本一致。
實現功能:
- 可以自動播放圖片
- 手指可以拖動播放輪播圖
下面詳細地說明具體的實現步驟:
1. 自動播放功能:
① 開啟定時器
② 移動端移動可以使用CSS3的translate移動。注意, 使用translate不需要添加就可以移動
③ 想要圖片優雅的移動,就需要添加過渡效果
2. 自動播放功能-無縫滾動:
① 注意,我們判斷條件是要等到圖片滾動完畢再去判斷,就是過渡完成后判斷
② 此時需要添加檢測過渡完成事件transitionend
③ 判斷條件:如果索引號等於3說明走到最后一張圖片,此時索引號要復原為0
④ 此時圖片需要去掉過渡效果,然后移動
PC端實現無縫滾動的原理是:克隆第一張圖片,然后添加到ul的最后面(appendChild)
- 把ul第一個li復制一份,放到ul的最后面
- 當圖片滾動到克隆的最后一張圖片時,讓ul快速的、不做動畫的跳到最左側:left為0
- 同時num賦值為0,可以從新開始滾動圖片了
在移動端照樣是使用這個方法,但是需要補充的是,由於在移動端可以使用手指拖動的效果,為了避免第一張再往前拖動的時候會出現空白的情況,我們還需要將最后一張圖片克隆放到第一張的前面去,也就是下面這樣:
注意,index是從第一張圖片算起的,並且克隆的第三張圖片是不能算作index里面去的。
3. 小圓點跟隨變化的效果:
① 把ol里面li帶有current類名的選出來去掉類名(remove)
② 讓當前索引號的小li加上current(add)(排他思想)
③ 但是,是等着過渡結束之后變化,所以這個功能要寫到transitionend事件里面
4. 手指滑動輪播圖
① 本質就是ul跟隨手指移動,簡單說就是移動端的拖動元素功能
② 觸摸元素:touchstart:獲取手指初始坐標
③ 移動手指touchmove:計算手指的滑動距離,並且移動盒子
④ 離開手指touchend:根據滑動的距離分不同的情況
⑤ 如果移動距離小於某個像素,就回彈到原來的位置
⑥ 如果移動距離大於某個像素就滑動到上一張或者下一張
性能優化1:當我們點擊輪播圖的圖片時,又不想移動了,這時候手指離開需要執行一大段代碼。優化辦法為:加一個flag全局變量,只有當手指真的移動了,才執行手指離開的一系列代碼操作
性能優化2:如果屏幕比較長,手指在移動輪播圖的過程可能會滾動屏幕。優化方法為:取消默認滾動屏幕的行為。在touchmove事件里加上e.preventDefault();即可。
<!-- 頁面布局 --> <div class="focus"> <ul> <li><img src="upload/focus3.jpg" alt=""></li> <li><img src="upload/focus1.jpg" alt=""></li> <li><img src="upload/focus2.jpg" alt=""></li> <li><img src="upload/focus3.jpg" alt=""></li> <li><img src="upload/focus1.jpg" alt=""></li> </ul> <!-- 輪播圖中的小圓圈 --> <ol> <li class="current"></li> <li></li> <li></li> </ol> </div> <!-- 焦點圖模塊 end -->
/* 焦點圖模塊樣式 */ .focus { overflow: hidden; position: relative; padding-top: 44px; } .focus img { width: 100%; } .focus ul { /* ul沒有高度,里面的子元素又是浮動的,必然會引起格式混亂 因此需要清除浮動 */ overflow: hidden; width: 500%; /* 顯示第一張圖片,而不是復制的第三張圖片 */ margin-left: -100%; } .focus ul li { float: left; /* 注意:圖片的寬度為100%,占滿父盒子,而圖片的父盒子小li沒有寬度,則找ul 而ul得寬度設為500%,所以圖片得寬度也被拉長了 因此需要給li設置寬度,每個小li占ul的1/5 */ width: 20%; } .focus ol { position: absolute; bottom: 5px; right: 5px; margin: 0; } .focus ol li { /* 使其變成行內塊元素,就可以浮動一排顯示 */ display: inline-block; width: 5px; height: 5px; border-radius: 2px; background-color: #fff; list-style: none; transition: all .3s; } .focus ol li.current { width: 15px; }
// JS邏輯代碼 window.addEventListener('load', function() { // 1. 獲取元素 var focus = document.querySelector('.focus'); var ul = focus.children[0]; var ol = focus.children[1]; // 獲得focus的寬度 var w = focus.offsetWidth; // 2. 利用定時器自動輪播圖片 var index = 0; var timer = setInterval(function() { index++; var translateX = -index * w; // 添加動畫效果 ul.style.transition = 'all .3s'; ul.style.transform = 'translateX(' + translateX + 'px)'; }, 2000); // 等着過渡完成之后,再去判斷,監聽過渡完成的事件transitionend ul.addEventListener('transitionend', function() { // 無縫滾動 if (index >= 3) { index = 0; // 去掉過渡效果,這樣讓ul快速的跳到目標位置 ul.style.transition = 'none'; // 利用最新的索引號乘以寬度,繼續滾動圖片 var translateX = -index * w; ul.style.transform = 'translateX(' + translateX + 'px)'; } else if (index < 0) { index = 2; // 去掉過渡效果,這樣讓ul快速的跳到目標位置 ul.style.transition = 'none'; // 利用最新的索引號乘以寬度,繼續滾動圖片 var translateX = -index * w; ul.style.transform = 'translateX(' + translateX + 'px)'; } // 3. 小圓點跟隨變化 // 把ol里面li帶有current類名的選出來,去掉類名remove ol.querySelector('.current').classList.remove('current'); // 讓當前索引號的li加上current類名add ol.children[index].classList.add('current'); }); // 4. 手指滑動輪播圖 // 觸摸元素touchstart:獲取手指初始坐標 var startX = 0; var moveX = 0; // 后面會使用這個移動距離,所以要定義為全局變量 var flag = false; //用來標志手指是否真的移動,還是只是點擊 ul.addEventListener('touchstart', function(e) { startX = e.targetTouches[0].pageX; // 手指觸摸的時候就停止定時器 clearInterval(timer); }); // 移動手指touchmove:計算手指的滑動距離,並且移動盒子 ul.addEventListener('touchmove', function(e) { // 計算移動距離 // e.targetTouches[0]為第一個手指,[1]表示第二個手指 moveX = e.targetTouches[0].pageX - startX; // 移動盒子:盒子原來的位置 + 手指移動的距離 var translateX = -index * w + moveX; // 手指拖動的時候,不需要動畫效果,所以要取消過渡效果 ul.style.transition = 'none'; ul.style.transform = 'translateX(' + translateX + 'px)'; flag = true; e.preventDefault(); //組織滾動屏幕的行為 }); // 手指離開,根據移動距離去判斷是回彈還是播放上一張或者下一張 ul.addEventListener('touchend', function(e) { // 只有手指移動過了,才執行下面的代碼 if (flag) { //(1)如果移動距離大於50像素,則播放上一張或者下一張 if (Math.abs(moveX) > 50) { // 如果是右滑就是播放上一張,moveX是正值 if (moveX > 0) { index--; } else { // 如果是左滑就是播放下一張,moveX是負值 index++; } // 用最新的index乘以寬度 var translateX = -index * w; ul.style.transition = 'all .3s'; ul.style.transform = 'translateX(' + translateX + 'px)'; } else { //(2)如果移動距離小於50像素就回彈 var translateX = -index * w; ul.style.transition = 'all .1s'; ul.style.transform = 'translateX(' + translateX + 'px)'; } } // 手指離開的時候就重新開啟定時器 // 注意:開啟定時器之前要先清空之前的定時器,保證當前只有一個定時器在執行 clearInterval(timer); timer = setInterval(function() { index++; var translateX = -index * w; // 添加動畫效果 ul.style.transition = 'all .3s'; ul.style.transform = 'translateX(' + translateX + 'px)'; }, 2000); }); });