在这篇文章中,我实现了一个基本的选项卡功能:请猛击后面的链接>>   [js插件开发教程]原生js仿jquery架构扩展开发选项卡插件.

还缺少两个常用的切换(自动切换与透明度渐变),当然有朋友会说,还有左右,上下等等,这些动画会放在焦点图(幻灯片)插件系列.

(自动切换,停止控制,透明度渐变 ) 效果预览:

自动切换的实现:

这个思路很简单,开启定时器,让选项卡的索引+1,加到4的时候(选项卡的长度)从0开始

传统做法:

index = 0

index++

if ( index == 4 ) {

index = 0

}

小技巧(估计很多人都没有用过):

var i = ( index + 1 ) %  4

index为当前选中的选项卡 索引

当index = 0,他下一张就是1,  通过上面的取余操作,i = 1

当index = 3,他下一张就是0, 通过上面的取余操作,i = 0

这种方法不需要判断边界,只需要一句代码。在实际开发中,把那个4替换成选项卡的长度

好了,关键的思路和技巧有了,我们开始拼接框架了:

         var defaults = {
contentClass : 'tab-content',
navClass : 'tab-nav',
activeClass : 'active',
triggerElements : '*',
activeIndex : 0,
evType : 'click',
effect : 'none',
auto : false,
delay : 3000,
duration : 1000
};

defaults参数,增加几个配置:

effect: none(没有特效) / fade( 透明度切换 )

auto: false(不会自动切换) / true ( 开启自动切换 )

delay : 多少时间 切换一个选项卡

duration: 透明度开启,这个才会用到,表示,多长时间内 完成透明度的切换

 if ( options.effect == 'fade' ) {
tabContent.style.position = 'relative';
for( var i = 0; i < tabContentEle.length; i++ ) {
tabContentEle[i].style.position = 'absolute';
}
tabContentEle[opt.activeIndex].style.zIndex = _contentLen + 1;
opt.delay += opt.duration;
}

当开启透明度变化的时候,把选项卡元素设置成定位方式,当前选中的选项卡,层级为最高!!! ( 如果不是最高层级,那么默认是最后一个选项卡在最上面,所以 “内容4” 就会在最上层,显然不是我们想要的结果)层级+定位 这一招也很常用,经常用来做显示隐藏,和透明度变化.

根据opt配置,判断是否开启了auto自动切换功能

  //是否自动播放
if ( opt.auto ) {
for( var i = 0 ; i < tabNavEle.length; i++ ){
tabNavEle[i].index = i;
tabNavEle[i].onmouseover = function(){
_api.stop();
_api.setIndex( this.index );
};
tabNavEle[i].onmouseout = function(){
_api.start();
_api.setIndex( this.index );
};
}
_api.start();
}

如果开启了,做两件事情:

1,调用start()函数,让索引+1

2,选项卡导航部分,添加事件控制 自动播放的暂停和开始

start与stop方法?

 _api.stop = function(){
timer && clearInterval( timer );
}; _api.start = function(){
_api.stop();
timer = setInterval( function(){
_api.next();
}, opt.delay );
};

调用next方法,你应该猜得到next方法做的事情就是索引+1 吧

  _api.next = function(){
var i = ( _index + 1 ) % _contentLen;
_api.setIndex( i );
};

索引+1之后,再切换选项卡

最后在setIndex方法:增加透明度变化

 if ( _index != index ) {
tabContentEle[_index].style.zIndex = _contentLen + 1;
for (var i = 0; i < tabContentEle.length; i++) {
if (i != _index) {
tabContentEle[i].style.zIndex = ( index + _contentLen - ( i + 1 ) ) % _contentLen + 1;
tabContentEle[i].style.opacity = 1;
}
}
animate(tabContentEle[_index], {'opacity': 0}, function () {
tabContentEle[_index].style.zIndex = ( index + _contentLen - ( _index + 1 ) ) % _contentLen + 1;
_index = index;
});
}

完整的js代码有220行:

 /**
* Created by ghostwu(吴华).
*/
(function(){
var G = function( selectors, context ){
return new G.fn.init( selectors, context );
}
G.fn = G.prototype = {
length : 0,
constructor : G,
size : function(){
return this.length;
},
init : function( selector, context ){
this.length = 0;
context = context || document;
if ( selector.indexOf( '#' ) == 0 ){
this[0] = document.getElementById( selector.substring( 1 ) );
this.length = 1;
}else {
var aNode = context.querySelectorAll( selector );
for( var i = 0, len = aNode.length; i < len; i++ ) {
this[i] = aNode[i];
}
this.length = len;
}
this.selector = selector;
this.context = context;
return this;
}
} G.fn.init.prototype = G.fn;
G.extend = G.fn.extend = function () {
var i = 1,
len = arguments.length,
dst = arguments[0],
j;
if (dst.length === undefined) {
dst.length = 0;
}
if (i == len) {
dst = this;
i--;
}
for (; i < len; i++) {
for (j in arguments[i]) {
dst[j] = arguments[i][j];
dst.length++;
}
}
return dst;
}; function css(obj, attr, value) {
if (arguments.length == 3) {
obj.style[attr] = value;
} else {
if (obj.currentStyle) {
return obj.currentStyle[attr];
} else {
return getComputedStyle(obj, false)[attr];
}
}
} function animate(obj, attr, fn) {
clearInterval(obj.timer);
var cur = 0;
var target = 0;
var speed = 0;
var start = new Date().getTime();//起始时间
obj.timer = setInterval(function () {
var bFlag = true;
for (var key in attr) {
if (key == 'opacity') {
cur = css(obj, 'opacity') * 100;
} else {
cur = parseInt(css(obj, key));
}
target = attr[key];
speed = ( target - cur ) / 8;
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
if (cur != target) {
bFlag = false;
if (key == 'opacity') {
obj.style.opacity = ( cur + speed ) / 100;
obj.style.filter = "alpha(opacity:" + ( cur + speed ) + ")";
} else {
obj.style[key] = cur + speed + "px";
}
}
}
if (bFlag) {
var end = new Date().getTime();//结束时间
console.log( '总计:', ( end - start ) );
clearInterval(obj.timer);
fn && fn.call(obj);
}
}, 30 );
} G.fn.tabs = function( options ){
options = options || {};
var defaults = {
contentClass : 'tab-content',
navClass : 'tab-nav',
activeClass : 'active',
triggerElements : '*',
activeIndex : 0,
evType : 'click',
effect : 'none',
auto : false,
delay : 3000,
duration : 1000
}; var opt = G.extend( {}, defaults, options ); var tabContent = this[0].querySelector( "." + opt.contentClass );
var tabContentEle = tabContent.children;
var tabNavEle = this[0].querySelectorAll( "." + opt.navClass + '>' + opt.triggerElements ); var _contentLen = tabContentEle.length; //选项卡个数
var _index = opt.activeIndex;
var timer = null; if ( options.effect == 'fade' ) {
tabContent.style.position = 'relative';
for( var i = 0; i < tabContentEle.length; i++ ) {
tabContentEle[i].style.position = 'absolute';
}
tabContentEle[opt.activeIndex].style.zIndex = _contentLen + 1;
opt.delay += opt.duration;
} var _api = {}; _api.next = function(){
var i = ( _index + 1 ) % _contentLen;
_api.setIndex( i );
}; _api.stop = function(){
timer && clearInterval( timer );
}; _api.start = function(){
_api.stop();
timer = setInterval( function(){
_api.next();
}, opt.delay );
}; _api.setIndex = function( index ){
//当前标签加上active样式,其余标签删除active样式
for ( var i = 0; i < _contentLen; i++ ) {
if ( tabNavEle[i].classList.contains( 'active' ) ) {
tabNavEle[i].classList.remove('active');
}
}
tabNavEle[index].classList.add( 'active' );
switch ( opt.effect ){
case 'fade':
if ( _index != index ) {
tabContentEle[_index].style.zIndex = _contentLen + 1;
for (var i = 0; i < tabContentEle.length; i++) {
if (i != _index) {
tabContentEle[i].style.zIndex = ( index + _contentLen - ( i + 1 ) ) % _contentLen + 1;
tabContentEle[i].style.opacity = 1;
}
}
animate(tabContentEle[_index], {'opacity': 0}, function () {
tabContentEle[_index].style.zIndex = ( index + _contentLen - ( _index + 1 ) ) % _contentLen + 1;
_index = index;
});
}
break;
default:
for ( var i = 0; i < _contentLen; i++ ) {
tabContentEle[i].style.display = 'none';
}
tabContentEle[index].style.display = 'block';
_index = index;
}
} _api.setIndex( _index ); //默认的选项卡 //所有的标签绑定事件
for( var i = 0, len = tabNavEle.length; i < len; i++ ) {
tabNavEle[i].index = i;
tabNavEle[i].addEventListener( opt.evType, function(){
var i = this.index;
_api.setIndex( i );
}, false );
} //是否自动播放
if ( opt.auto ) {
for( var i = 0 ; i < tabNavEle.length; i++ ){
tabNavEle[i].index = i;
tabNavEle[i].onmouseover = function(){
_api.stop();
_api.setIndex( this.index );
};
tabNavEle[i].onmouseout = function(){
_api.start();
_api.setIndex( this.index );
};
}
_api.start();
} return this;
} var $ = function( selectors, context ){
return G( selectors, context );
}
window.$ = $;
})();

[js插件开发教程]实现一个比较完整的开源级选项卡插件的更多相关文章

  1. [js插件开发教程]定制一个手风琴插件(accordion)

    本文带来一个垂直方向的手风琴插件开发,可以定制的功能如下: contentClass : 'panel', //面板样式navClass : 'nav', //导航样式activeClass : 'a ...

  2. [js插件开发教程]一步步开发一个可以定制配置的隔行变色小插件

    隔行变色功能,不用js,直接用css伪类就可以做,这个实例可以作为js插件开发很好的入门级实例.本文实现的隔行变色包括以下功能: 1,支持2种常用结构共存( div元素 和 表格类型 ) 2,一个页面 ...

  3. [js插件开发教程]原生js仿jquery架构扩展开发选项卡插件

    jquery插件一般是这么干的: $.fn.插件名称 = function(){}, 把插件的名称加在.fn上,在源码里面实际上是扩展到构造函数的原型对象上,如果你没看过jquery的源代码,或者你曾 ...

  4. jQuery插件开发教程

    jQuery插件开发教程  ——让你的jQuery水平提升一个台阶 要说jQuery 最成功的地方,我认为是它的可扩展性吸引了众多开发者为其开发插件,从而建立起了一个生态系统.这好比大公司们争相做平台 ...

  5. (转)跟我一起学JQuery插件开发教程

    在逛codeproject网站的时候,突然看到一篇文章:How to write plugin in Jquery. 如果对E文好的同学 ,可以看上面的连接.现在我把上面网站的及结合自己的想法写这篇文 ...

  6. Js插件开发

    简易JS插件开发,本文效果是一个简单的弹出层,意在记录插件的封装Demo. 完整源码压缩包:demo.rar 效果图(如下): 插件脚本: /** * 节点配置属性方式配置参数:专业的做法是配置到,每 ...

  7. 跟我一起学JQuery插件开发教程

    在逛codeproject网站的时候,突然看到一篇文章:How to write plugin in Jquery. 如果对E文好的同学 ,可以看上面的连接.现在我把上面网站的及结合自己的想法写这篇文 ...

  8. 分享我对JS插件开发的一些感想和心得

    本文阅读目录: •起因•如何开发一个轻量级的适用性强的插件•总结 起因 如果大家平时做过一些前端开发方面的工作,一定会有这样的体会:页面需要某种效果或者插件的时候,我们一般会有两种选择: 1.上网查找 ...

  9. js插件开发的一些感想和心得

    起因 如果大家平时做过一些前端开发方面的工作,一定会有这样的体会:页面需要某种效果或者插件的时候,我们一般会有两种选择:1.上网查找相关的JS插件,学习其用法2.自己造轮子,开发插件. 寻找存在的插件 ...

随机推荐

  1. 学号:201521123116 《java程序设计》第四周学习总结

    1. 本周学习总结 2. 书面作业 Q1. 注释的应用使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看.(截图)答:注释的插入:注释以/开始,以/结束类注释/**.... ...

  2. 201521123045-----《Java程序设计》第3周学习总结

    ---恢复内容开始--- 1. 本章学习总结 2. 书面作业 1. 代码阅读 public class Test1 { private int i = 1;//这行不能修改 private stati ...

  3. Java中如何引入结对编程

    引自微信: 很多同学说: 我程序写得好,ACM比赛能得分, 就好了,软件工程讲的那些有用么? 有些学校的 <软件工程>课,由于要求太简单,反而不能说明软件工程的价值. 其实好办, 让学生结 ...

  4. hibernate中Query的list和iterator区别

    1.Test_query_list类 public class Test_query_iterator_list { public static void main(String[] args) { ...

  5. Scanner(键盘录入)

    注意事件: 1: 当使用Scanner类时 切记不要做从键盘输入一个int数 再输入一个字符串 这样会导致bug就是字符串会读取不到几所输入的内容 原因是因为:当你用了NextInt()方法时,再按了 ...

  6. Opencv的使用,NDK的简单使用

    第一部分:安装运行: 1.下载opencv,并解压,将其目录下的sdk复制到eclipse的工作区间目录下,重命名为OpenCV-SDK(随意命名): 2.从eclipse中导入:file->i ...

  7. 封装好的图片滑动框架(AndroidImageSlider)

    前言 广告轮播条的重要性不言而喻.在很多类型app中出场率都很高. 今天给大家介绍一个轮播图开源项目,这个项目把轮播图需要的ViewPager跟计时器做了封装,使用极其方便,支持gradle在线依赖. ...

  8. JS 数据处理技巧及小算法汇总( 一)

    前言: 金秋九月的最后一天,突然发现这个月博客啥也没更新,不写点什么总觉得这个月没啥长进,逆水行舟,不进则退,前进的路上贵在坚持,说好的每个月至少一到两篇,不能半途而废!好多知识写下来也能加深一下自身 ...

  9. HSF服务的开发与使用

    1.HSF服务的开发 1) 基于Maven创建一个web工程HSFService,如下图,其他的可以自定义. 2)创建好好在src/main目录下创建一个java目录,并将其设置为sources fo ...

  10. Beauty Contest 凸包+旋转卡壳法

    Beauty Contest Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 27507   Accepted: 8493 D ...