在做行動裝置開發的時候,必不可少的是輪播圖,以下這篇文章主要給大家介紹了關於利用純JS實現行動端web輪播圖的相關資料,重要的是結合Tween演算法造輪子,文中透過範例程式碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
前言
相信大家應該都知道,行動端的輪播圖是我們比較常見的需求, 我們最快的實現方式往往是使用第三方的程式碼, 例如swiper , 但當遇到一些比較複雜的輪播圖需求時, 往往是束手無策,不知道怎麼改.
#所以我們要嘗試去自己造一些輪子, 以適應各種複雜多變的需求; 另外一點, 自己寫的代碼如果有bug是很容易修復的, 對自身的提高也很大.
在沒有閱讀swiper源碼的過程下,我嘗試自己實現一個簡易而不失實用的移動端輪播圖, 經過幾個小時的思考和實踐終於還是實現了(如圖):
#實現行動端的輪播圖比pc複雜一些,主要表現在以下幾個方面:
1.輪播圖要適應不同寬度/dpr的螢幕
2.需要使用touch相關的事件
3.不同機型對touch事件支援的不太一樣,可能會有一些相容性問題
4.手指移動圖片一部分距離,剩餘的距離需要自動完成
5.自動完成距離需要有ease 時間曲線
## 5.自動完成距離需要有ease 時間曲線
#但程式解決問題的想法都是差不多的,
我們在使用輪播圖的時候可以仔細觀察,透過現像看到本質:
##圖片輪播是無限循環的, 我們需要採用 3 1 2 3 1的方式來實現, 即N+2張圖來實現N張圖的無限循環輪播
我們透過分析現象,可以提出一個基本實現方案:
1. 手指觸摸事件可以透過touchstart touchmove touchend 3個事件來實現
2.在手指touchstart的時候我們需要記錄手指的x座標, 可以使用touch的pageX屬性; 還有這個時間點,
實作原始碼(僅供參考):
head頭部樣式
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=.5,maximum-scale=.5"> <title>移动端轮播图</title> <style> * { box-sizing: border-box; margin: 0; padding: 0 } .banner { overflow: hidden; width: 100%; height: 300px } .banner .img-wrap { position: relative; height: 100% } .banner img { display: block; position: absolute; top: 0; width: 100%; height: 100% } </style> </head>
HTML結構
#
<p class="banner"> <p class="img-wrap" id="imgWrap"> <img src="images/banner_3.jpg" data-index="-1"> <img src="images/banner_1.jpg" data-index="0"> <img src="images/banner_2.jpg" data-index="1"> <img src="images/banner_3.jpg" data-index="2"> <img src="images/banner_1.jpg" data-index="3"> </p> </p>JS程式碼1, easeOut動畫式移動,
<script> HTMLElement.prototype.tweenTranslateXAnimate = function (start, end, callback) { var duration = 50; var t = 0; var vv = end - start; var Tween = { Quad: { easeOut: function (t, b, c, d) { return -c * (t /= d) * (t - 2) + b; } } }; this.timer = setInterval(function () { var dis = start + Tween.Quad.easeOut(++t, 0, vv, duration); this.style.transform = 'translate3d(' + dis + 'px, 0, 0)'; if (vv > 0 && parseInt(this.style.transform.slice(12)) >= end) { this.style.transform = 'translate3d(' + parseInt(dis) + 'px, 0, 0)'; clearInterval(this.timer); callback && callback(); } if (vv < 0 && parseInt(this.style.transform.slice(12)) <= end) { this.style.transform = 'translate3d(' + parseInt(dis) + 'px, 0, 0)'; clearInterval(this.timer); callback && callback(); } }.bind(this), 4); } </script>
touch事件部分
<script> ~function () { var lastPX = 0; // 上一次触摸的位置x坐标, 需要计算出手指每次移动的一点点距离 var movex = 0; // 记录手指move的x方向值 var imgWrap = document.getElementById('imgWrap'); var startX = 0; // 开始触摸时手指所在x坐标 var endX = 0; // 触摸结束时手指所在的x坐标位置 var imgSize = imgWrap.children.length - 2; // 图片个数 var t1 = 0; // 记录开始触摸的时刻 var t2 = 0; // 记录结束触摸的时刻 var width = window.innerWidth; // 当前窗口宽度 var nodeList = document.querySelectorAll('#imgWrap img'); // 所有轮播图节点数组 NodeList // 给图片设置合适的left值, 注意 querySelectorAll返回 NodeList, 具有 forEach方法 nodeList.forEach(function (node, index) { node.style.left = (index - 1) * width + 'px'; }); /** * 移动图片到当前的 tIndex索引所在位置 * @param {number} tIndex 要显示的图片的索引 * */ function toIndex(tIndex) { var dis = -(tIndex * width); var start = parseInt(imgWrap.style.transform.slice(12)); // 动画移动 imgWrap.tweenTranslateXAnimate(start, dis, function () { setTimeout(function () { movex = dis; if (tIndex === imgSize) { imgWrap.style.transform = 'translate3d(0, 0, 0)'; movex = 0; } if (tIndex === -1) { imgWrap.style.transform = 'translate3d(' + width * (1 - imgSize) + 'px, 0, 0)'; movex = -width * (imgSize - 1); } }, 0); }); } /** * 处理各种触摸事件 ,包括 touchstart, touchend, touchmove, touchcancel * @param {Event} evt 回调函数中系统传回的 js 事件对象 * */ function touch(evt) { var touch = evt.targetTouches[0]; var tar = evt.target; var index = parseInt(tar.getAttribute('data-index')); if (evt.type === 'touchmove') { var di = parseInt(touch.pageX - lastPX); endX = touch.pageX; movex += di; imgWrap.style.webkitTransform = 'translate3d(' + movex + 'px, 0, 0)'; lastPX = touch.pageX; } if (evt.type === 'touchend') { var minus = endX - startX; t2 = new Date().getTime() - t1; if (Math.abs(minus) > 0) { // 有拖动操作 if (Math.abs(minus) < width * 0.4 && t2 > 500) { // 拖动距离不够,返回! toIndex(index); } else { // 超过一半,看方向 console.log(minus); if (Math.abs(minus) < 20) { console.log('距离很短' + minus); toIndex(index); return; } if (minus < 0) { // endX < startX,向左滑动,是下一张 toIndex(index + 1) } else { // endX > startX ,向右滑动, 是上一张 toIndex(index - 1) } } } else { //没有拖动操作 } } if (evt.type === 'touchstart') { lastPX = touch.pageX; startX = lastPX; endX = startX; t1 = new Date().getTime(); } return false; } imgWrap.addEventListener('touchstart', touch, false); imgWrap.addEventListener('touchmove', touch, false); imgWrap.addEventListener('touchend', touch, false); imgWrap.addEventListener('touchcancel', touch, false); }(); </script>在觸控事件中最關鍵的參數是 pageX參數, 記錄x的位置.當然這只是一個demo,還需要進一步的優化和封裝, 以便於我們用在真實的項目.
以上是詳解如何使用原生JS實現行動裝置web輪播圖效果的詳細內容。更多資訊請關注PHP中文網其他相關文章!