zoukankan      html  css  js  c++  java
  • 移动web:tab选项卡

      平常做移动端会用到tab选项卡,这和PC端有些区别,移动端是触摸滑动切换,PC端是点击、移入切换。

      这里滑动切换就是一个移动端事件的应用,这里主要用到的触摸事件:touchstart、touchmove、touchend。

      和做其他的效果一样,先有html结构,css样式修饰,再写JS代码。

      html:

    <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:

    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代码,供参考

    /**
     * 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; } } }());

      使用方式很简单,如下

    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选项卡下载

  • 相关阅读:
    BZOJ 3531[Sdoi2014]旅行
    BZOJ4998 星球联盟
    BZOJ2959 长跑
    【北京集训D2T3】tvt
    [Bzoj]5343: [Ctsc2018]混合果汁
    HGOI20190810 省常中互测3
    HGOI20190809 省常中互测2
    HGOI20190808 省常中互测1
    组合排列和组合数 学习笔记
    2-SAT (two-statisfiability) 算法 学习笔记
  • 原文地址:https://www.cnblogs.com/eyeear/p/4613643.html
Copyright © 2011-2022 走看看