高手莫入,浅显例子而已。最近在更换项目中的javascript库,觉得如果能把实践的过程记录下来,应该可以帮助到一些对javascript感兴趣的前端初学者,@胖子哥,是吧。
我们常常看到网站上有一些可以切换的选项卡,那么这些选项卡是怎么制作的呢。
首先看一个简单的栗子-v-
http://thecdn.sinaapp.com/page/demo/jq-tab-switch/
那么这样的效果是怎么实现的呢。
我们来一步一步分解任务,首先在纸上把你的需求草图画一下。我鼠绘比较丑,PS随便拖几个色块,如图所示。
首先这个选项卡是分两个部分的,上面一条比较窄的是导航按钮,下面比较大面积的是展示内容。导航按钮中又包含了一些深红色的按钮。
接着想一下用户和这个选项卡的交互,比如鼠标划过会切换内容,或者点击会切换内容。再往深一点想,内容是怎么切换。
比如你要使用Ajax的XHR来填充内容,还是使用已经存在的数据,比如CALLBACK回来的JSON来动态填充,还是简单的切换隐藏页面内已经存在的内容。切换内容你又要使用神马形式的特效,是淡入淡出,还是左飞出,还是对角线移动…
好了,把心思收回来,先从简单的开始。先用HTML把刚刚的想法的草图实现一下。
关于结构,大家仁者见仁,我觉得下面的结构用来展示还是比较不错的。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JQUERY TAB SWITCH</title>
</head>
<body>
<div id="tab-warp">
<ul class="tab-label">
<li class="tab-label-item hover">标签A</li>
<li class="tab-label-item">标签B</li>
<li class="tab-label-item">标签C</li>
<li class="tab-label-item">标签D</li>
</ul>
<ul class="tab-panel">
<li class="tab-panel-item hover">
<p>我欲与君相知,长命无绝衰。 山无陵,江水为竭,冬雷震震,夏雨雪, 天地合,乃敢与君绝!...</p>
</li>
<li class="tab-panel-item">
<p>愿得一心人,白头不相离。</p>
</li>
<li class="tab-panel-item">
<p>得成比目何辞死愿作鸳鸯不羡仙。</p>
</li>
<li class="tab-panel-item">
<p>身无彩凤双飞翼心有灵犀一点通。</p>
</li>
</ul>
</div>
</body>
</html>
结构展示:
http://thecdn.sinaapp.com/page/demo/jq-tab-switch/step-1.html
现在貌似很丑陋,没关系,你可以用CSS来美化一下它。当然,作为例子,我就不细致的去搞它了。
使用下面的CSS就能看出一个大概的样子,足够下一步写JS使用的样式。
*,html,body,div,ul,li,h3,p{
margin: 0;
padding: 0;
}
body{
background-color:#caefff;
}
div,ul,li,h3,p{
float: left;
display: block;
}
div#tab-warp{
width: 400px;
height: 200px;
top: 50%;
left: 50%;
position: absolute;
margin-left: -200px;
margin-top: -200px;
}
div#tab-warp ul.tab-label, div#tab-warp ul.tab-panel{
width:100%;
}
div#tab-warp ul.tab-label{
height: 30px;
border-bottom: none;
}
div#tab-warp ul.tab-panel{
background-color: #a3cadc;
height: 150px;
border: 2px solid #fff;
}
ul.tab-label li.tab-label-item{
background-color: #555;
width: 50px;
height: 24px;
line-height: 24px;
font-weight: normal;
margin-top: 5px;
border: 1px solid #EEE;
color: white;
text-align: center;
cursor: pointer;
}
ul.tab-label li.tab-label-item.hover{
background-color: #64AEFF;
width: 60px;
height: 29px;
line-height: 29px;
font-weight: bold;
margin-top: 0;
}
ul.tab-panel li.tab-panel-item{
width: 100%;
height: 100%;
color: #434343;
display: none;
}
ul.tab-panel li.tab-panel-item p{
margin:10px;
}
ul.tab-panel li.tab-panel-item.hover{
display: block;
}
样式展示: http://thecdn.sinaapp.com/page/demo/jq-tab-switch/step-2.html
如果上一步添加样式,让你觉得这个选项卡有点丑,那么你可以继续在上一步精雕细琢,完成你要的选项卡样式。 如果你完成了,或者你想看如何把交互内容添加到选项卡上,那么我们继续。
在页面中引入jQuery库后我们开始写可以让选项卡活起来的代码,接下来的说明都会写到注释中。
$(document).ready(
//如果网络速度不佳,页面结构没有下载完毕
//这时脚本先于文档结构解析完毕的时候执行或许会出错
//所以我们使用这个方法把主要的逻辑代码包裹起来
//对应HTML文档中的选项卡的上部的导航标签
//获取这货的所有子元素,然后为他们绑定一个事件:鼠标点击
$('div#tab-warp>ul.tab-label').children().bind("click",
function(e) {
//当鼠标点击后
//先分别获取选项卡两个部分的子元素
var nav = $('div#tab-warp>ul.tab-label').children();
var pal = $('div#tab-warp>ul.tab-panel').children();
//判断他们的子元素数量是否一致
var navc = nav.length;
var palc = nav.length;
//如果不一致,那么没有办法正常切换,所以不继续执行
if (navc != palc) {
return;
}
//去掉所有的按钮的class中的'hover'
for (var i = 0; i < navc; i++) {
$(nav[i]).removeClass('hover');
}
//给当前点击的元素的class中添加'hover'
$(this).addClass('hover');
var o = 0;
//定义一个变量获取当前具有焦点的元素的序号(index)
//然后获取当前的具有'hover'的元素的序号
for (var i = 0; i < navc; i++) {
//如果某个元素被选中,那么这个元素的class包含'hover'
if ($(nav[i]).hasClass('hover')) {
//注意这里因为一一对应,下面注释有说
o = i;
}
}
//因为上边的选项卡按钮和下面的内容是一一对应的。
//所以内容和选项卡进行同样的操作
//去掉所有内容class中的'hover'
pal.removeClass('hover');
//接着给和按钮序号一样的家伙添加一个'hover'属性
$(pal[o]).addClass('hover');
//最后终止事件冒泡
e.stopPropagation();
}
)
);
交互展示: http://thecdn.sinaapp.com/page/demo/jq-tab-switch/step-3.html
在这一步,你可以给你的选项卡切换添加不同的特效或者根据不同的事件触发,比如鼠标移动到元素上,或者按下了某个键盘按键等。
那么这样写法固定的脚本意义大嘛,个人感觉不大,既然这个东西有共性,那么我们应该把这个家伙抽象出来,变成一个公共的东西。
jQuery提供一种叫做插件的形式来组织这样可以公共使用的内容。
在此之前,我们需要把插件中效率不是太高的方法,重写一下。
$(document).ready(
//首先是绑定元素替换为绑定元素的父级,统称事件代理,
//这个事件中绑定导航按钮的父元素可以有效缩减3次绑定
$('div#tab-warp>ul.tab-label').parent().bind('click',
//把点击事件传到e这个参数中
//让函数中可以引用
function(e) {
//对e.target元素进行处理
//触发的元素得到了鼠标的眷顾哦
//先来判断下是不是我们要的按钮元素
//我们要的按钮元素的class具备tab-label-item
//所以没有这个class属性的元素,就不和他玩了
if (!$(e.target).hasClass('tab-label-item')) {
return;
}
var nav = $('div#tab-warp>ul.tab-label').children();
var pal = $('div#tab-warp>ul.tab-panel').children();
var navc = nav.length;
var palc = nav.length;
if (navc != palc) {
return;
}
//把之前的循环也用已经缓存了的对象来操作吧
nav.removeClass('hover');
//之前的this到这里要修改为假定的目标元素
$(e.target).addClass('hover');
var o = 0;
for (var i = 0; i < navc; i++) {
if ($(nav[i]).hasClass('hover')) {
o = i;
}
}
pal.removeClass('hover');
$(pal[o]).addClass('hover');
e.stopPropagation();
}
)
);
简单优化: http://thecdn.sinaapp.com/page/demo/jq-tab-switch/step-4.html
假定上面的javascript优化的差不多了,我们就可以制作插件了。
//为了保护世界的和平
//为了防止世界被破坏
//先把内容扔匿名函数中
;
(function($) {
//用覆盖的方式写插件
$.fn.extend({
//插件就叫switchTab吧
//传入一个对象类型的参数叫做params
//之前的固定的字符串修改为参数
// 'div#tab-warp>ul.tab-label' ==> params.tabNav
// 'div#tab-warp>ul.tab-panel' ==> params.tabPan
// 'tab-label-item' ==> params.tabNavBtn
// 'hover' ==> params.hover
// 'click' ==> params.event
//接着我们调用的时候传入的参数大概就是这样
//params ==> {
// tabNav:'div#tab-warp>ul.tab-label',
// tabPan:'div#tab-warp>ul.tab-panel',
// tabNavBtn:'tab-label-item',
// hover:'hover',
// event:'click'
// }
"switchTab": function(params) {
//设置参数默认值
params = $.extend({
tabNav: 'div#tab-warp>ul.tab-label', //导航按钮的容器
tabPan: 'div#tab-warp>ul.tab-panel', //对应的内容的容器
tabNavBtn: 'tab-label-item', //导航按钮的元素
hover: 'hover', //获得焦点后要添加的css类名
event: 'click' //要绑定的事件类型
}, params);
//这里开始之前的函数内容
$(document).ready(
$(params.tabNav).parent().bind(params.event,
function(e) {
if (!$(e.target).hasClass(params.tabNavBtn)) {
return;
}
var nav = $(params.tabNav).children();
var pal = $(params.tabPan).children();
var navc = nav.length;
var palc = nav.length;
if (navc != palc) {
return;
}
nav.removeClass(params.hover);
$(e.target).addClass(params.hover);
var o = 0;
for (var i = 0; i < navc; i++) {
if ($(nav[i]).hasClass(params.hover)) {
o = i;
}
}
pal.removeClass(params.hover);
$(pal[o]).addClass(params.hover);
e.stopPropagation();
}
)
);
//这里结束之前函数内容
return this; //返回插件本身
//让插件可以链式操作
}
});
})(jQuery, 'SOULTEARY.COM');
//第一个参数是传入我们要选项卡化的元素
//最后就是插件化的意义
//简单的传入参数实现调用
$('#tab-warp').switchTab({
tabNav: 'div#tab-warp>ul.tab-label',
tabPan: 'div#tab-warp>ul.tab-panel',
tabNavBtn: 'tab-label-item',
hover: 'hover',
event: 'click'
});
插件化: http://thecdn.sinaapp.com/page/demo/jq-tab-switch/step-5.html
最后抽离所有的内联元素,让页面略微规范。
最后结果: http://thecdn.sinaapp.com/page/demo/jq-tab-switch/index.html
至此这篇肤浅的文章就结束了,希望路过的前端爱好者可以从这里获取一点点的知识。
如果有任何的疑问,或者勘误,欢迎留言斧正。