移動web:圖片切換(焦點圖)

  在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 -->
View Code

  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;
}
View Code

  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;
    }
}
}());
View Code

  效果預覽 (Chrome的移動模式、移動設備)this

  • 1
  • 2
  • 3
  • 4

   這個根據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;
}
View Code

   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;
     } 
}
}());
View Code

  導航指示根據有幾張圖片來建立 (滑動切換容器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數據生成標籤)……無論它怎麼變,只要掌握基本的原理,問題都能解決。

  下載圖片切換(焦點圖)

相關文章
相關標籤/搜索