移動web:tab選項卡

  日常作移動端會用到tab選項卡,這和PC端有些區別,移動端是觸摸滑動切換,PC端是點擊、移入切換。css

  這裏滑動切換就是一個移動端事件的應用,這裏主要用到的觸摸事件:touchstart、touchmove、touchend。html

  和作其餘的效果同樣,先有html結構,css樣式修飾,再寫JS代碼。node

  html:css3

<div class="mtabs" id="tabs">
    <ul class="mhead">
        <li>tab1</li>
        <li>tab2</li>
        <li>tab3</li>
    </ul>
    <div class="mcontent">
        <ul>
            <li>tab1內容內容內容內容</li>
            <li>tab1內容內容內容內容</li>
            <li>tab1內容內容內容內容</li>
            <li>tab1內容內容內容內容</li>
            <li>tab1內容內容內容內容</li>
        </ul>
        <ul>
            <li>tab2內容內容內容內容</li>
            <li>tab2內容內容內容內容</li>
            <li>tab2內容內容內容內容</li>
            <li>tab2內容內容內容內容</li>
            <li>tab2內容內容內容內容</li>
        </ul>
        <ul>
            <li>tab3內容內容內容內容</li>
            <li>tab3內容內容內容內容</li>
            <li>tab3內容內容內容內容</li>
            <li>tab3內容內容內容內容</li>
            <li>tab3內容內容內容內容</li>
        </ul>
    </div>
</div><!-- End .mtabs -->
View Code

  css:web

body,div,ul,li{
    margin:0;
    padding:0;
}
ul,li {
    list-style:none;
}
body {
    font-size:100%;
    font-family:Helvetica,STHeiti,Droid Sans Fallback;
}
.mtabs {
    width:100%;
    overflow:hidden;
}
.mhead {
    height:38px;
    border-top:2px solid #9ac7ed;
    background:#ECF2F6;
    -webkit-tap-highlight-color:rgba(0,0,0,0);
}
.mhead li {
    position:relative;
    font-size:1.125em;
    text-align:center;
    float:left;
    width:64px;
    height:38px;
    line-height:38px;
    color:#2a70be;
}
.mhead li.current {
    border-top:2px solid #2a70be;
    margin-top:-2px;
    background:#FFF;
    color:#c14545;
}
.mcontent {
    width:100%;
    overflow:hidden;
}
.mcontent ul {
    width:100%;
    float:left;
}
.mcontent li {
    height:35px;
    line-height:35px;
    font-size:1.125em;
    padding:0 10px;
}
View Code

  下面的截圖是想要的一個效果預覽:數組

  

   下面是實際效果,能夠在Chrome的移動模式查看:瀏覽器

  • tab1
  • tab2
  • tab3
  • tab1內容內容內容內容
  • tab1內容內容內容內容
  • tab1內容內容內容內容
  • tab1內容內容內容內容
  • tab1內容內容內容內容
  • tab2內容內容內容內容
  • tab2內容內容內容內容
  • tab2內容內容內容內容
  • tab2內容內容內容內容
  • tab2內容內容內容內容
  • tab3內容內容內容內容
  • tab3內容內容內容內容
  • tab3內容內容內容內容
  • tab3內容內容內容內容
  • tab3內容內容內容內容

   先貼上JS代碼,供參考css3動畫

/**
 * LBS mTabs
 * Date: 2014-5-10
 * ===================================================
 * 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;
     //取得tabs外圍容器、標題容器、內容容器
	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,'');
		}//初始化設置、先清空手動加在標題或內容HTML標籤的當前類名(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.mhead.addEventListener("click",function(e){ _this.touchClick(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 100ms'; 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.mcontent.style.webkitTransition = this.mcontent.style.transition = 'all 300ms'; 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'; }, touchClick: function(e){ var target = e.target; if(target.nodeType === 1 && target.index !== undefined){ if(target.index === this.index) return; e.preventDefault(); e.stopPropagation(); this.index = target.index; this.mcontent.style.webkitTransition = this.mcontent.style.transition = 'all 100ms'; //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.replace(); } }, 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; } } }());

  使用方式很簡單,以下ide

document.addEventListener('DOMContentLoaded',function(){
	//use mTabs
	new mTabs({
		mtab: '#tabs',
		mhead: '#tabs .mhead',
		mcontent: '#tabs .mcontent'
	});

	/*new mTabs({
		mtab: '#tabs',
		mhead: '#tabs .mhead',
		mcontent: '#tabs .mcontent',
		index: 1,
		current: 'active'
	});*/

},false);
mtab: 
<div class="mtabs" id="tabs">
    //..    
</div>
mhead:
<ul class="mhead">
    //..
</ul>
mcontent:
<div class="mcontent">
    //..
</div> 

 

  在此說下思路:動畫

    先得到一個tabs容器對象(mtab),它包含了兩個對應的類集合容器,一個是標籤欄(mhead)、一個是內容欄(mcontent),再分別取得類集合容器裏面對應的選項mheads、mcontents。

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;

    獲取設備瀏覽器窗口的寬,並更新內容容器(mcontent)的寬,內容項的寬,通常在頁面都會有文檔聲明 <!DOCTYPE html> document.documentElement.clientWidth 就能獲取瀏覽器窗口的寬。

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';

    在手指觸摸按上時(在tabs容器對象上), 獲取手指按下時在頁面的位置 ( e.touches[0].pageX)。 touchs想象成有幾根手指,只須要第一根按下的手指( touches[0] )。初始化了一個行爲判斷 this.touch.fixed (當在tabs上滑動時是要滾動頁面仍是要切換選項卡)。

this.touch.x = e.touches[0].pageX;
//..
this.touch.fixed = '';

  在移動手指時,作出行爲的判斷。先得到移動的距離(左右方向、上下方向),根據兩個方向的值比較判斷是哪一種行爲。

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';
	}
}

   在移動手指時,內容容器(mcontent)也會跟着移動,而且作了在處於第一項和最後一項時的移動限制。

if( (this.index === 0 && this.touch.disX > 0) || (this.index === this.length-1 && this.touch.disX < 0) ) this.touch.disX /= 4; 

   在手指離開屏幕的時候,作出切換判斷,是向左仍是向右。在第一項時,不能向左切換,最後一項時不能向右切換。

this.touch.disX > 0 ? this.index-- : this.index++;
this.index < 0 && (this.index = 0);
this.index > this.length - 1 && (this.index = this.length - 1);

   最後是真正的移動切換,用了css3動畫切換,translateX 或者 translate3d .

//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方法,配合webkitTransitionEnd事件在動畫切換執行完成時調用。這裏調用這個方法是用來清除動畫定義的持續時間。

transitionEnd: function(){
	this.mcontent.style.webkitTransition = this.mcontent.style.transition = 'all 0ms';
}

this.mcontent.addEventListener('webkitTransitionEnd',function(){
	_this.transitionEnd();
}, false);

   點擊切換是判斷點擊了哪一項,在初始設置時已經爲每一項保存了索引值(index),根據對應的索引值,切換選項,更新狀態。能夠循環綁定點擊事件,也可使用事件委託,這裏使用的是事件委託。

this.mheads[i].index = i;

touchClick: function(e){
	var target = e.target;
	if(target.nodeType === 1 && target.index !== undefined){
		//..
		this.index = target.index;
		//..
		this.mcontent.style.webkitTransform = this.mcontent.style.transform = "translate3d(" + (-this.index * this.width) + "px,0,0)";
		
	}
}

this.mhead.addEventListener("click",function(e){
	_this.touchClick(e);
}, false);

   tab選項卡主要是得到兩組對應的相似集合(一組標籤,一組內容),兩個相似數組都有索引值(數組下標),經過這個索引值,作出對應的切換。獲取索引值是tab選項卡的關鍵,移動web端的選項卡主要是增長了觸摸事件操做這個索引值。加上定時器,每隔多少時間增長或者減小這個索引值,自動播放也就完成了。會了tab選項卡也就會了圖片的切換,焦點圖什麼的,原理都是同樣。 

   tab選項卡下載

相關文章
相關標籤/搜索