在这篇文章中,我实现了一个基本的选项卡功能:请猛击后面的链接>>   [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. 201521123036 《Java程序设计》第1周学习总结

    本周学习总结 本周的课是Java的入门.了解了Java的发展过程,运用平台,可跨平台的便利性.懂得jdk,jre,jvm的概念及区别.熟悉Java开发工具,掌握java程序的编译执行的详细过程. 书面 ...

  2. 控制结构(8) 线性化(linearization)

    // 上一篇:管道(pipeline) // 下一篇:程序计数器(PC) "编程语言不过是一个工具,什么语言都一样","编程语言能改变人的思维,不同的语言会带给你不同的思 ...

  3. 201521123025《java程序设计》第12周学习总结

    #1. 本周学习总结 #2. 书面作业 将Student对象(属性:int id, String name,int age,double grade)写入文件student.data.从文件读出显示. ...

  4. markdown编辑器的学习

    markdown编辑器的学习 1 标题 一级标题 二级标题 三级标题 四级标题 五级标题 六级标题 2列表 无序列表 1 2 3 4 有序列表 1 2 3 4 3引用 这里是引用,哈哈我也不知道到我引 ...

  5. django的admin或者应用中使用KindEditor富文本编辑器

    由于django后台管理没有富文本编辑器,看着好丑,展示出来的页面不美观,无法做到所见即所得的编辑方式,所以我们需要引入第三方富文本编辑器. 之前找了好多文档已经博客才把这个功能做出来,有些博客虽然写 ...

  6. 微信bug:建议了解,不要实验,不要手贱,不要。。。。

    今天下午在群里聊天的时候,群友反应发现微信的一个bug:使用微信给好友发送‘15...............’(数字15后面加15个句号)会导致微信运行缓慢,到最后的应用未响应,退出微信. 解决办法 ...

  7. Go语言备忘录:基本数据结构

    本文内容是本人对Go语言的变量.常量.数组.切片.映射.结构体的备忘录,记录了关键的相关知识点,以供翻查. 文中如有错误的地方请大家指出,以免误导!转摘本文也请注明出处,多谢! 参考书籍<Go语 ...

  8. Java虚拟机-运行时数据区域

    Java虚拟机管理的内存包括如图所示的运行时数据区域: 下面分别进行介绍: 1)程序计数器(Program Counter Register) 占用的内存空间比较小,主要作用就是标识当前线程执行的字节 ...

  9. pdf点击超链接后返回:alt+ 向左 /向右

    pdf点击超链接后返回:alt+ 向左 /向右

  10. URL编码解决

    与其他系统对接时遇到的问题URL中传递认证码,URL默认只允许传递ASCII码中的数据,所以浏览器默认会进行一次编码将%等特殊符号转义后台web服务器收到URL中的参数,会默认进行一次解码,但遇到的问 ...