序
相信大家都應該知道,移動端的輪播是壹個普遍的需求。我們最快的實現方式往往是使用第三方代碼,比如swiper,但是當我們遇到壹些復雜的輪播需求時,往往會手足無措,不知道怎麽改。
所以,我們要努力自己造壹些輪子,滿足各種復雜多變的需求;另壹方面,如果妳自己的代碼有bug,很容易修復並大大提高自己。
在沒有看swiper源代碼的情況下,嘗試自己實現了壹個簡單實用的移動輪播,經過幾個小時的思考和練習終於實現了(如圖):
在移動端實現輪播比pc端更復雜,主要表現在以下幾個方面:
1.傳送帶應適應不同寬度/dpr的屏幕。
2.需要使用觸摸相關事件
3.不同型號支持觸摸事件不同,可能會有壹些兼容性問題。
4.用手指移動壹部分距離,剩下的需要自動完成。
5.自動完成距離需要壹條緩和時間曲線。
但是編程解決問題的思路都差不多。
我們在使用旋轉木馬的時候,可以仔細觀察,透過現象看本質:
我們在使用旋轉木馬的時候,可以仔細觀察,透過現象看本質:
將手指放在圖片上,向左或向右移動手指,圖片會隨之移動;
手指移動壹點距離,畫面自動恢復位置;手指長時間移動,會自動切換到下壹個;
當手指向左或向右快速移動時,會切換到下壹個;
圖片輪播是無限循環的,我們需要采用3 1 2 3 1的方式,即N+2張圖片來實現N張圖片的無限循環輪播。
通過分析這壹現象,我們可以提出壹個基本的實施方案:
1.手指觸摸事件可以通過三個事件實現:觸摸開始觸摸移動觸摸。
2.我們需要記錄手指touchstart時手指的X坐標,可以使用touch的pageX屬性;這個時間點,
3.我們還需要在touchmove和移動手指時記錄pageX,並記錄累積移動距離moveX。
4.當手指離開時,記錄時間點,根據前面兩步計算出的在X方向移動的距離,以及時間點之間的差值。
5.通過比較X方向的移動距離判斷移動方向,是否切換到下壹張圖片;根據時間判斷用戶是否左右滑動。
6.使用translate3d可以實現運動畫面,並且開啟了硬件加速。
7.移動壹段距離需要easeOut效果。我們可以使用補間算法中的easeOut來實現我們每次移動的距離。當然也可以用js來設置轉場動畫。
實現源碼(僅供參考):
頭頭風格
& lthead & gt
& ltmeta charset="UTF-8 " >
& ltmeta name = " viewport " content = " width = device-width,initial-scale=.5,maximum-scale=.5 " >
& lttitle & gt移動旋轉木馬
& ltstyle & gt
* {
框大小:邊框-框;
邊距:0;
填充:0
}
。橫幅{
溢出:隱藏;
寬度:100%;
高度:300像素
}
。橫幅。img-wrap {
位置:相對;
身高:100%
}
。橫幅圖像{
顯示:塊;
位置:絕對;
top:0;
寬度:100%;
身高:100%
}
& lt/style & gt;
& lt/head & gt;HTML結構
& ltp class="banner " >
& ltp class="img-wrap" id="imgWrap " >
& ltimg src = " images/banner _ 3 . jpg " data-index = "-1 " >
& ltimg src = " images/banner _ 1 . jpg " data-index = " 0 " >
& ltimg src = " images/banner _ 2 . jpg " data-index = " 1 " >
& ltimg src = " images/banner _ 3 . jpg " data-index = " 2 " >
& ltimg src = " images/banner _ 1 . jpg " data-index = " 3 " >
& lt/p & gt;
& lt/p & gt;JS代碼1,easeOut動畫運動,
HtmlElement。原型。這裏的tweentranslatexanimate是所有HTML元素類的擴展tweentranslatexanimate方法。
移動壹段距離,我們需要用壹個計時器來幫助我們完成這個重復的操作。
& lt腳本& gt
html element . prototype . tweentranslatexanimate = function(start,end,callback) {
var持續時間= 50;
var t = 0;
var vv =結束-開始;
var Tween = {
四元組:{
easeOut: function (t,b,c,d) {
return-c *(t/= d)*(t-2)+b;
}
}
};
this . timer = setInterval(function(){
var dis =開始+補間。Quad.easeOut(++t,0,vv,duration);
this . style . transform = ' translate 3d('+dis+' px,0,0)';
if(vv & gt;0 & amp& ampparse int(this . style . transform . slice(12))& gt;= end) {
this . style . transform = ' translate 3d('+parse int(dis)+' px,0,0)';
clear interval(this . timer);
回撥和。& amp回調();
}
if(vv & lt;0 & amp& ampparse int(this . style . transform . slice(12))& lt;= end) {
this . style . transform = ' translate 3d('+parse int(dis)+' px,0,0)';
clear interval(this . timer);
回撥和。& amp回調();
}
}.綁定(this),4);
}
& lt/script & gt;觸摸事件部分
& lt腳本& gt
~function () {
var lastPX = 0;//最後壹次觸摸的位置X坐標需要計算手指每次移動的壹點距離。
var movex = 0;//記錄手指移動的X方向值。
var img wrap = document . getelementbyid(' img wrap ');
var startX = 0;//開始觸摸時手指的X坐標。
var endX = 0;//觸摸結束時手指的X坐標位置。
var img size = img wrap . children . length-2;//圖片數量
var t 1 = 0;//記錄開始觸摸的時間。
var T2 = 0;//記錄觸摸結束的時間。
var width = window.innerWidth//當前窗口寬度
var nodeList = document . query selector all(' # img wrap img ');//所有轉盤節點數組的節點列表
//為圖片設置壹個合適的左值。請註意,querySelectorAll使用forEach方法返回壹個NodeList。
nodeList.forEach(function (node,index) {
node . style . left =(index-1)* width+' px ';
});
/**
*將圖片移動到當前tIndex的位置。
* @param {number} tIndex要顯示的圖片的索引。
* */
函數toIndex(tIndex) {
var dis =-(tIndex * width);
var start = parse int(img wrap . style . transform . slice(12));
//動畫移動
img wrap . tweentranslatexanimate(start,dis,function () {
setTimeout(function () {
movex = dis
if (tIndex === imgSize) {
img wrap . style . transform = ' translate 3d(0,0,0)';
movex = 0;
}
if (tIndex === -1) {
img wrap . style . transform = ' translate 3d('+width *(1-img size)+' px,0,0)';
movex =-width *(img size-1);
}
}, 0);
});
}
/**
*處理各種觸摸事件,包括觸摸開始、觸摸結束、觸摸移動和觸摸取消。
系統在evt回調函數中返回的* @ param {event} js事件對象。
* */
功能觸摸(evt) {
var touch = evt . target touches[0];
var tar = evt.target
var index = parse int(tar . get attribute(' data-index '));
if (evt.type === 'touchmove') {
var di = parse int(touch . pagex-lastPX);
endX = touch.pageX
movex+= di;
img wrap . style . webkittransform = ' translate 3d('+movex+' px,0,0)';
lastPX = touch.pageX
}
if (evt.type === 'touchend') {
var MINUS = endX-startX;
t2 =新日期()。getTime()-t 1;
if (Math.abs(減號)& gt0) {//有拖動操作。
if (Math.abs(減號)& lt寬度* 0.4 & amp& ampt2 & gt500) {//拖動距離不夠,返回!
toIndex(索引);
} else {//過半,看方向
console.log(減號);
if (Math.abs(減號)& lt20) {
Console.log('短距離'+減號);
toIndex(索引);
返回;
}
if(減& lt0){//endX & lt;StartX,向左滑動,就是下壹個。
toIndex(index + 1)
} else {//endX & gt;StartX,向右滑動,是上壹個。
toIndex(索引- 1)
}
}
} else {//沒有拖動操作。
}
}
if (evt.type === 'touchstart') {
lastPX = touch.pageX
startX = lastPX
endX = startX
t1 =新日期()。getTime();
}
返回false
}
img wrap . addevent listener(' touch start ',touch,false);
img wrap . addevent listener(' touch move ',touch,false);
img wrap . addevent listener(' touch end ',touch,false);
img wrap . addevent listener(' touch cancel ',touch,false);
}();
& lt/script & gt;觸摸事件中最關鍵的參數是pageX參數,它記錄了x的位置.
當然,這只是壹個演示,還需要進壹步的優化和封裝,這樣我們才能在真實的項目中使用。
這個演示只是提供了壹個解決問題的思路。有了這個思路,相信各種復雜的需求都可以解決。...