在web頁面上圖片切換(焦點圖)效果實在是太常見了,PC端、移動端處處都有它的身影。css
上次寫了個tab選項卡的效果,在這裏延續一下,改爲圖片切換的效果。html
若是不須要自動播放,稍微修改下html標籤、和css樣式,tab選項卡JS裏動畫持續時間、去掉點擊切換事件部分就能夠了。web
htmlapp
<div class="mslide" id="slide"> <ul class="mcontent"> <li><a href="#a1"><img src="images/01.jpg" /></a></li> <li><a href="#a2"><img src="images/02.jpg" /></a></li> <li><a href="#a3"><img src="images/03.jpg" /></a></li> <li><a href="#a4"><img src="images/04.jpg" /></a></li> </ul> <ul class="mhead"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> </div><!-- End mslide -->
csside
body,div,ul,li{margin:0;padding:0;} ul,li{list-style: none;} body{font-size: 100%; font-family: Helvetica,STHeiti,Droid Sans Fallback;} .mslide { position:relative; width:100%; overflow:hidden; margin: 15px 0; } .mcontent { width:100%; overflow:hidden; } .mcontent li { width:100%; float:left; } .mcontent li img { width:100%; } .mhead { position:absolute; bottom:5px; left:0; z-index: 10; text-align:center; width:100%; height:15px; line-height:15px; } .mhead li { display:inline-block; width:10px; height:10px; border:1px solid #999; border-radius:6px; margin:0 3px; overflow:hidden; font-size:0; line-height:0; vertical-align: top; background: transparent; color:rgba(0,0,0,0); } .mhead li.current { background:#F00; }
JS動畫
/** * LBS mTabs (修改爲圖片切換) * =================================================== * opts.mtab tabs外圍容器/滑動事件對象(一個CSS選擇器) * opts.mhead tabs標題容器/點擊對象(一個CSS選擇器) * opts.mcontent tabs內容容器/滑動切換對象(一個CSS選擇器) * opts.index tabs索引(默認0) 指定顯示哪一個索引的標題、內容 * opts.current tabs當前項的類名(默認current) * =================================================== **/ ;(function(){ window.mTabs = function(opts){ if(typeof opts === undefined) return; this.mtab = document.querySelector(opts.mtab); this.mhead = document.querySelector(opts.mhead); this.mcontent = document.querySelector(opts.mcontent); this.mheads = this.mhead.children; this.mcontents = this.mcontent.children; this.length = this.mheads.length; if(this.length < 1) return; if(opts.index > this.length-1) opts.index = this.length-1; this.index = this.oIndex = opts.index || 0; this.current = opts.current || 'current'; this.touch = {}; this.init(); } mTabs.prototype = { init: function(opts){ this.set(); this.initset(); this.bind(); }, initset: function(){ for(var i = 0; i < this.length; i++){ this.mheads[i].index = i; this.mheads[i].className = this.mheads[i].className.replace(this.current,''); this.mcontents[i].className = this.mcontents[i].className.replace(this.current,''); } this.mheads[this.index].className += ' '+this.current; this.mcontents[this.index].className += ' '+this.current; //this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translateX(" + (-this.index * this.width) + "px)"; this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translate3d(" + (-this.index * this.width) + "px,0,0)"; }, set: function(){ this.width = document.documentElement.clientWidth || document.body.clientWidth; this.mcontent.style.width = this.length * this.width + 'px'; for(var i = 0; i < this.length; i++) this.mcontents[i].style.width = this.width + 'px'; //this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translateX(" + (-this.index * this.width) + "px)"; this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translate3d(" + (-this.index * this.width) + "px,0,0)"; }, bind: function(){ var _this = this; this.mtab.addEventListener("touchstart",function(e){ _this.touchStart(e); }, false); this.mtab.addEventListener("touchmove",function(e){ _this.touchMove(e); }, false); this.mtab.addEventListener("touchend",function(e){ _this.touchEnd(e); }, false); this.mtab.addEventListener("touchcancel",function(e){ _this.touchEnd(e); }, false); this.mcontent.addEventListener('webkitTransitionEnd',function(){ _this.transitionEnd(); }, false); window.addEventListener("resize", function(){ setTimeout(function(){ _this.set(); },100); }, false); window.addEventListener("orientationchange",function(){ setTimeout(function(){ _this.set(); },100); }, false); }, touchStart: function(e){ this.touch.x = e.touches[0].pageX; this.touch.y = e.touches[0].pageY; this.touch.time = Date.now(); this.touch.disX = 0; this.touch.disY = 0; this.touch.fixed = ''; }, touchMove: function(e){ if(this.touch.fixed === 'up') return; e.stopPropagation(); if(e.touches.length > 1 || e.scale && e.scale !== 1) return; this.touch.disX = e.touches[0].pageX - this.touch.x; this.touch.disY = e.touches[0].pageY - this.touch.y; if(this.touch.fixed === ''){ if( Math.abs(this.touch.disY) > Math.abs(this.touch.disX) ){ this.touch.fixed = 'up'; }else{ this.touch.fixed = 'left'; } } if(this.touch.fixed === 'left'){ e.preventDefault(); if( (this.index === 0 && this.touch.disX > 0) || (this.index === this.length-1 && this.touch.disX < 0) ) this.touch.disX /= 4; //this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translateX(" + ( this.touch.disX - this.index * this.width ) + "px)"; this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translate3d(" + ( this.touch.disX - this.index * this.width ) + "px,0,0)"; } }, touchEnd: function(e){ if(this.touch.fixed === 'left'){ var _this = this, X = Math.abs(this.touch.disX); this.mcontent.style.webkitTransition = this.mcontent.style.transition = 'all 400ms'; if( (Date.now() - this.touch.time > 100 && X > 10) || X > this.width/2 ){ this.touch.time = Date.now(); this.touch.disX > 0 ? this.index-- : this.index++; this.index < 0 && (this.index = 0); this.index > this.length - 1 && (this.index = this.length - 1); if(this.index !== this.oIndex) this.replace(); } //this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translateX(" + (-this.index * this.width) + "px)"; this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translate3d(" + (-this.index * this.width) + "px,0,0)"; } }, transitionEnd: function(){ this.mcontent.style.webkitTransition = this.mcontent.style.transition = 'all 0ms'; }, replace: function(){ this.mheads[this.index].className += ' '+this.current; this.mheads[this.oIndex].className = this.mheads[this.oIndex].className.replace(this.current,'').trim(); this.mcontents[this.index].className += ' '+this.current; this.mcontents[this.oIndex].className = this.mcontents[this.oIndex].className.replace(this.current,'').trim(); this.oIndex = this.index; } } }());
效果預覽 (Chrome的移動模式、移動設備)this
這個根據tab選項卡修改而成的圖片切換能適應大部分web頁面的需求。點擊下載spa
如今來加上自動播放功能,在上面的html,css基礎上作出一點修改,每次手動寫入導航的指示的html標籤太麻煩了,讓程序來判斷有幾張圖片,而後建立幾個導航指示,這樣html結構更簡潔。prototype
html3d
<div class="mslide" id="slideIMG"> <ul class="mcontent"> <li><a href="#a1"><img src="images/01.jpg" /></a></li> <li><a href="#a2"><img src="images/02.jpg" /></a></li> <li><a href="#a3"><img src="images/03.jpg" /></a></li> <li><a href="#a4"><img src="images/04.jpg" /></a></li> </ul> </div><!-- End mslide -->
css
body,div,ul,li{margin:0;padding:0;} ul,li{list-style: none;} body{font-size: 100%; font-family: Helvetica,STHeiti,Droid Sans Fallback;} .mslide { position:relative; width:100%; overflow:hidden; margin: 15px 0; } .mcontent { width:100%; overflow:hidden; } .mcontent li { width:100%; float:left; } .mcontent li img { width:100%; } .mhead { position:absolute; bottom:5px; left:0; z-index: 10; text-align:center; width:100%; height:15px; line-height:15px; } .mhead li { display:inline-block; width:10px; height:10px; border:1px solid #999; border-radius:6px; margin:0 3px; overflow:hidden; font-size:0; line-height:0; vertical-align: top; background: transparent; color:rgba(0,0,0,0); } .mhead li.current { background:#F00; }
JS代碼和tab選項卡大部分類似,增長了自動播放、建立導航指示。
先貼JS出代碼,供參考
/** * LBS mSlideIMG 順序版-自動 * Date: 2014-5-11 * =================================================== * opts.mslide 外圍容器/滑動事件對象(一個CSS選擇器) * opts.mcontent 內容容器/滑動切換對象(一個CSS選擇器) * opts.index 索引(默認0) 指定顯示哪一個索引的導航指示、圖片項 * opts.navclass 導航容器的類名(默認mnav) * opts.current 當前項的類名(默認current) * opts.auto 是否自動播放 默認false * opts.delay 自動播放間隔時間 默認5秒 自動播放時有效 * opts.duration 動畫持續時間 默認400ms * =================================================== **/ ;(function(){ window.mSlideIMG = function(opts){ if(typeof opts === undefined) return; this.mslide = document.querySelector(opts.mslide); this.mcontent = document.querySelector(opts.mcontent); this.mcontents = this.mcontent.children; this.mnav = null; this.mnavs = []; this.length = this.mcontents.length; if(this.length < 1) return; if(opts.index > this.length-1) opts.index = this.length-1; this.index = this.oIndex = opts.index || 0; this.current = opts.current || 'current'; this.navclass = opts.navclass || 'mnav'; this.duration = opts.duration || 400; this.auto = !!opts.auto || false; this.auto && (this.delay = opts.delay || 5); this.timer = null; this.touch = {}; this.init(); } mSlideIMG.prototype = { init: function(opts){ this.set(); this.initset(); this.bind(); }, initset: function(){ this.create(); for(var i = 0; i < this.length; i++){ if(getComputedStyle(this.mcontents[i],null).position === 'absolute') this.mcontents[i].style.position = 'relative'; if(getComputedStyle(this.mcontents[i],null).cssFloat !== 'left') this.mcontents[i].style.cssFloat = 'left'; } this.mnavs[this.index].className = this.current; this.mcontents[this.index].className += ' '+this.current; //this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translateX(" + (-this.index * this.width) + "px)"; this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translate3d(" + (-this.index * this.width) + "px,0,0)"; }, set: function(){ this.width = document.documentElement.clientWidth || document.body.clientWidth; this.mcontent.style.width = this.length * this.width + 'px'; for(var i = 0; i < this.length; i++) this.mcontents[i].style.width = this.width + 'px'; //this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translateX(" + (-this.index * this.width) + "px)"; this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translate3d(" + (-this.index * this.width) + "px,0,0)"; }, create: function(){ this.mnav = document.createElement('ul'), li = null, i = 0; for(; i < this.length; i++){ li = document.createElement('li'); li.innerHTML = i+1; this.mnavs.push(li); this.mnav.appendChild(li); } this.mnav.className = this.navclass; this.mslide.appendChild(this.mnav); }, bind: function(){ var _this = this; this.mslide.addEventListener("touchstart",function(e){ _this.touchStart(e); _this.auto && _this.stop(); }, false); this.mslide.addEventListener("touchmove",function(e){ _this.touchMove(e); _this.auto && _this.stop(); }, false); this.mslide.addEventListener("touchend",function(e){ _this.touchEnd(e); _this.auto && _this.start(); }, false); this.mslide.addEventListener("touchcancel",function(e){ _this.touchEnd(e); _this.auto && _this.start(); }, false); this.mcontent.addEventListener('webkitTransitionEnd',function(){ _this.transitionEnd(); }, false); window.addEventListener("resize", function(){ setTimeout(function(){ _this.set(); },100); }, false); window.addEventListener("orientationchange",function(){ setTimeout(function(){ _this.set(); },100); }, false); this.auto && this.start(); }, touchStart: function(e){ this.touch.x = e.touches[0].pageX; this.touch.y = e.touches[0].pageY; this.touch.time = Date.now(); this.touch.disX = 0; this.touch.disY = 0; this.touch.fixed = ''; }, touchMove: function(e){ if(this.touch.fixed === 'up') return; e.stopPropagation(); if(e.touches.length > 1 || e.scale && e.scale !== 1) return; this.touch.disX = e.touches[0].pageX - this.touch.x; this.touch.disY = e.touches[0].pageY - this.touch.y; if(this.touch.fixed === ''){ if( Math.abs(this.touch.disY) > Math.abs(this.touch.disX) ){ this.touch.fixed = 'up'; }else{ this.touch.fixed = 'left'; } } if(this.touch.fixed === 'left'){ e.preventDefault(); if( (this.index === 0 && this.touch.disX > 0) || (this.index === this.length-1 && this.touch.disX < 0) ) this.touch.disX /= 4; //this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translateX(" + ( this.touch.disX - this.index * this.width ) + "px)"; this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translate3d(" + ( this.touch.disX - this.index * this.width ) + "px,0,0)"; } }, touchEnd: function(e){ if(this.touch.fixed === 'left'){ var _this = this, X = Math.abs(this.touch.disX); if( (Date.now() - this.touch.time > 100 && X > 10) || X > this.width/2 ){ this.touch.time = Date.now(); this.touch.disX > 0 ? this.index-- : this.index++; this.index < 0 && (this.index = 0); this.index > this.length - 1 && (this.index = this.length - 1); if(this.index !== this.oIndex) this.replace(); } this.mcontent.style.webkitTransition = this.mcontent.style.transition = 'all '+ this.duration +'ms'; //this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translateX(" + (-this.index * this.width) + "px)"; this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translate3d(" + (-this.index * this.width) + "px,0,0)"; } }, transitionEnd: function(){ this.mcontent.style.webkitTransition = this.mcontent.style.transition = 'all 0ms'; }, replace: function(){ this.mnavs[this.index].className = this.current; this.mnavs[this.oIndex].className = ''; this.mcontents[this.index].className += ' '+this.current; this.mcontents[this.oIndex].className = this.mcontents[this.oIndex].className.replace(this.current,'').trim(); this.oIndex = this.index; }, start : function(){ if(this.length < 2) return; var _this = this; this.timer = setInterval(function(){ _this.index++; _this.index > _this.length - 1 && (_this.index = 0); if(_this.index !== _this.oIndex) _this.replace(); _this.mcontent.style.webkitTransition = _this.mcontent.style.transition = 'all '+ _this.duration +'ms'; //_this.mcontent.style.webkitTransform = _this.mcontent.style.transform = "translateX(" + (-_this.index * _this.width) + "px)"; _this.mcontent.style.webkitTransform = _this.mcontent.style.transform = "translate3d(" + (-_this.index * _this.width) + "px,0,0)"; },this.delay*1000); }, stop : function(){ clearInterval(this.timer); this.timer = null; } } }());
導航指示根據有幾張圖片來建立 (滑動切換容器ul.mcontent -> 包裹圖片li標籤,這裏就是判斷有幾個li標籤)
this.mcontent = document.querySelector(opts.mcontent); this.mcontents = this.mcontent.children; //.. this.length = this.mcontents.length; //.. create: function(){ this.mnav = document.createElement('ul'), li = null, i = 0; for(; i < this.length; i++){ li = document.createElement('li'); li.innerHTML = i+1; this.mnavs.push(li); this.mnav.appendChild(li); } this.mnav.className = this.navclass; this.mslide.appendChild(this.mnav); }
自動播放是間隔一段時間改變一個索引值來實現的,這個索引值在開始的時候默認定義爲0。每間隔一段時間,這個索引值增長1。
this.index = this.oIndex = opts.index || 0; //.. start : function(){ //.. this.timer = setInterval(function(){ _this.index++; _this.index > _this.length - 1 && (_this.index = 0); //.. _this.mcontent.style.webkitTransition = _this.mcontent.style.transition = 'all '+ _this.duration +'ms'; _this.mcontent.style.webkitTransform = _this.mcontent.style.transform = "translate3d(" + (-_this.index * _this.width) + "px,0,0)"; },this.delay*1000); }
有時候要清除自動播放,當用手指來切換圖片時,要清除自動播放,手指離開時又開始自動播放。
stop : function(){ clearInterval(this.timer);//清除定時 this.timer = null; } //.. this.mslide.addEventListener("touchstart",function(e){ _this.touchStart(e); _this.auto && _this.stop(); //手指移入 若是有自動播放則清除 }, false); this.mslide.addEventListener("touchend",function(e){ _this.touchEnd(e); _this.auto && _this.start(); //手指離開 從新開始自動播放 }, false);
有時同一個web頁面,有好幾個圖片切換,但願有的能定時自動切換,有的不用定時,爲程序增長一個接口設置是否自動播放,順便把間隔時間,切換動畫持續時間一塊兒定義了。
this.auto = !!opts.auto || false; //默認沒有自動播放 this.auto && (this.delay = opts.delay || 5); //默認間隔時間5秒 this.duration = opts.duration || 400; //默認動畫持續時間400毫秒
自動播放的圖片切換,差很少完成了,來看下效果 (Chrome的移動模式、移動設備)。
說一些要注意的地方,外圍容器(這裏是類名爲mslide的div標籤)要設置相對或者絕對定位、並溢出隱藏;圖片容器(這裏是li標籤)要浮動,爲了都顯示在一排滾動的容器(這裏是類名爲mcontent的ul標籤)要足夠寬;新建的導航指示是相對於外圍容器絕對定位的,注意層級問題(這些能在樣式裏面定義就在樣式裏定義,程序爲了全面能夠多作判斷)。
這個圖片切換當最後一項切換到第一項時,動畫跨度大,方向也和前幾回相反,有時須要更天然的切換,方向都同樣,每次動畫距離也同樣,這是一種進價的圖片切換(焦點圖),也叫無縫切換。說下思路:能夠採用絕對定位方式(這個例子裏的li標籤絕對定位,在li標籤上作動畫切換) ,根據索引值,在切換前修正位置,切換完成後修正位置;能夠採用複製節點方式(複製這個例子裏的li標籤、所有或者部分),根據索引值判斷修正位置(這個例子裏動畫切換的對象和要修正位置對象是mcontent)。
能夠看下效果:
實際上根據業務需求,會作出不一樣的改變,好比圖片要切換到那一項時才加載,圖片切換在頁面沒有html標籤(解析JSON數據生成標籤)……無論它怎麼變,只要掌握基本的原理,問題都能解決。