移动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 -->
css:
- body,div,ul,li{
- margin:;
- padding:;
- }
- 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;
- }
下面的截图是想要的一个效果预览:
下面是实际效果,可以在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选项卡也就会了图片的切换,焦点图什么的,原理都是一样。
移动web:tab选项卡的更多相关文章
- tab选项卡实例
之前也见了不少的tab选项卡,但是下面这个选项卡是一个页面中有多个时互不影响的. <head> <meta charset="utf-8"> <met ...
- 基于CkEditor实现.net在线开发之路(4)快速布局,工具箱,模板载入,tab选项卡简单说明与使用
上一章给常用的from表单控件属性页面,进行了简单说明和介绍,但是由于是在网页中做界面设计,操作肯定没有桌面应用程序方便,便捷,为了更方便的布局与设计,今天我主要说一下快速布局,工具箱,tab选项卡, ...
- 可轮播滚动的Tab选项卡
前段时间有试着搭建个后台主题ui框架,有用到可支持滚动的Tab选项卡,模仿着H+后台主题ui框架中的代码造轮子改造了下,可惜代码在公司,不能把代码外发出来(感觉这样被限制了很多,对于这样的公司没办法, ...
- android tab选项卡的使用
项目做完了,写写博客,在项目中遇到的一些问题,或者是自己觉得很不错的东西.这一篇主要是想和大家分享一下我在项目中封装的一个东西,就是tab选项卡.先看看效果图: 我在网上看了很多有关选项卡的demo, ...
- js基础练习一之tab选项卡
最近在学习前端,当然包括js,css,html什么的,在听课时做的一些小练习,记录下来: 实例一: --Tab选项卡-- <script type="text/javascript&q ...
- :target伪类制作tab选项卡
:target伪类的作用是突出显示活动的HTML锚,下面是一个简单的例子: HTML代码: <div> <a href="#demo1">点击此处</ ...
- 工作当中实际运用(1)——tab选项卡
不废话 直接上代码: tab选项卡 window.onload=function(){ var titles= document.getElementById('header-dh').getElem ...
- 各种效果的tab选项卡
;(function($){ $.fn.tabso=function( options ){ var opts=$.extend({},$.fn.tabso.defaults,options ); r ...
- (2)WinForm中改变Tab选项卡的顺序
Tab选项卡选中,在其属性中找到TabPages这个属性.点进去,可以通过上下移动标签卡改变标签卡的顺序.
随机推荐
- shell脚本查看网络配置
#!/bin/bash ifconfig|grep -E 'eth|inet'|grep -Ev '(inet6|127.0.0.1)'|sed 's/ /\n/g'|awk NF|grep -Ev ...
- HDU 3571 N-dimensional Sphere(高斯消元 数论题)
这道题算是比较综合的了,要用到扩展欧几里得,乘法二分,高斯消元. 看了题解才做出来orz 基本思路是这样,建一个n*(n-1)的行列式,然后高斯消元. 关键就是在建行列式时会暴long long,所以 ...
- CacheHelper工具类的使用
package com.bbcmart.util; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import ne ...
- hdu4513(manacher)
传送门:吉哥系列故事——完美队形II 题意:求最长回文队伍且队伍由中间向两边递减. 分析:manach算法小应用,在判断回文子串向两边递减时加点限制使回文是由中间向两边递减的. #pragma com ...
- Dark Side of Cloud Storage —— 数据对像的分块消重
数据对像(可以通俗地认为是文件)的分块存储具有久远的历史.长久以来,单机文件系统一直将文件切分为若干固定大小的小块.其主要目的是为了进行有效的空间管理.互联网时代,大规模数据存储逐步发展起来.出于降低 ...
- ssh 即使主机,同nohup背景脚本
下面的脚本工具:先从本地副本的脚本到远程主机,然后ssh即使在远程主机,脚本的运行副本前(因为脚本需要运行很长,它运行在后台),该脚本仅用于备忘录,如果请指点不足! #!/bin/bash cd /t ...
- 轻松学习之Linux教程六 正則表達式具体解释
本系列文章由@超人爱因斯坦出品.转载请注明出处. 作者:超人爱因斯坦 个人站点:http://www.hpw123.net 文章链接:http://hpw123.net/a/L ...
- Java中定时器的使用
import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.T ...
- Python数据结构-序表
序表解包: list=['aa','bb','cc'] [a1,a2,a3]=list
- WPF疑难杂症会诊
原文:WPF疑难杂症会诊 为什么图片像素是模糊的? 容器边框设为非整数时,其内容中的像素图片会产生模糊,即使设置SnapsToDevicePixels="True"也无效. 以下是 ...