[js插件开发教程]原生js仿jquery架构扩展开发选项卡插件
jquery插件一般是这么干的: $.fn.插件名称 = function(){}, 把插件的名称加在.fn上,在源码里面实际上是扩展到构造函数的原型对象上,如果你没看过jquery的源代码,或者你曾经看过,但是不知道为什么把插件扩展到fn上,那么本篇文章就能解答你的疑惑。关于jquery插件开发方式,可以参考我的这篇文章:[js高手之路]jquery插件开发实战-选项卡详解
关于选项卡这个功能具体怎么做,不在这里详解,这个是入门级的功能,本文重在讨论插件开发的架构,扩展,以及参数设置。
如果你使用过jquery的选项卡插件,或者其他类型的插件,他们一般都是这么调用的:
$( ".tab" ).tabs( {} )
$(".tab").tabs( function(){} );
一种是传递参数定制插件行为
一种是传递函数定制插件行为
$(".tab") 选择到元素,然后返回的是jquery对象
tabs方法扩展在fn上就是扩展都jquery构造函数的原型对象上, 那么对象( $(".tab") )调用原型对象上的方法( tabs )当然就顺利成章了。
所以jquery插件扩展本质就是: 构造函数 + 原型对象扩展方法
定义一个构造+原型的方式,下面代码的原理,我在这篇文章有详细论述:[js高手之路] 设计模式系列课程 - jQuery的链式调用与灵活的构造函数
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;
};
在这篇文章:[js高手之路] 设计模式系列课程 - jQuery的extend插件机制 有详细的论述,extend插件扩展机制
像使用jquery一样暴露接口:
var $ = function( selectors, context ){
return G( selectors, context );
}
window.$ = $;
这个插件的扩展机制和元素选择机制就完成了,如果要扩展插件,只要在
G.fn上扩展插件的名称即可,如:
G.fn.tabs = function( options ){
options = options || {};
var defaults = {
contentClass : 'tab-content',
navClass : 'tab-nav',
activeClass : 'active',
triggerElements : '*',
activeIndex : 0,
evType : 'click',
effect : 'none'
}; var opt = G.extend( {}, defaults, options );
return this;
}
这样,我们就在G的原型对象上扩展了一个tabs( 选项卡 )插件
options可以定制插件的行为:
contentClass : 'tab-content', 选项卡内容区域的class名称
navClass : 'tab-nav', 标签卡区域的class名称
activeClass : 'active', 标签卡默认选择的class名称:active
triggerElements : '*', 标签卡默认触发元素
activeIndex : 0, 默认选中第几个标签卡
evType : 'click', 选项卡触发的事件类型
effect : 'none' 是否有过渡特效:如透明度 var opt = G.extend( {}, defaults, options );
这一段是把定制的配置和默认配置合成到一个对象opt里面,后面的插件行为,就可以根据opt的配置进行定制,这是插件开发参数定制中,常用的一招。
这样做的好处,可以防止污染默认配置defaults
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;
获取对应的元素。
有了选项卡的元素和配置,我们就开始做业务处理(为所有选项卡添加处理的事件,进行选项卡切换)
定义一个专门的对象_api = {}, 扩展业务api
G.fn.tabs = function( options ){
options = options || {};
var defaults = {
contentClass : 'tab-content',
navClass : 'tab-nav',
activeClass : 'active',
triggerElements : '*',
activeIndex : 0,
evType : 'click',
effect : 'none'
}; 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 _api = {}; _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':
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 );
} return this;
}
完整的插件代码:
/**
* 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;
}; G.fn.tabs = function( options ){
options = options || {};
var defaults = {
contentClass : 'tab-content',
navClass : 'tab-nav',
activeClass : 'active',
triggerElements : '*',
activeIndex : 0,
evType : 'click',
effect : 'none'
}; 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 _api = {}; _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':
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 );
} return this;
} var $ = function( selectors, context ){
return G( selectors, context );
}
window.$ = $;
})();
选项卡布局:
<!DOCTYPE html>
<html>
<head lang="en">
<!--作者:ghostwu(吴华)-->
<meta charset="UTF-8">
<title>选项卡插件 - by ghostwu</title>
<link rel="stylesheet" href="css/tab.css"/>
<script src="./js/tab.js"></script>
<script>
window.onload = function () {
// console.log( $(".tab1 .tab-nav li") );
// $( ".tab1" ).tabs( { 'evType' : 'mouseenter' } );
$( ".tab1" ).tabs();
}
</script>
</head>
<body>
<div class="main">
<div class="tab tab1">
<ul class="tab-nav">
<li class="active"><a href="javascript:;">标签1</a></li>
<li><a href="javascript:;">标签2</a></li>
<li><a href="javascript:;">标签3</a></li>
<li><a href="javascript:;">标签4</a></li>
</ul>
<div class="tab-content">
<p>内容1</p>
<p>内容2</p>
<p>内容3</p>
<p>内容4</p>
</div>
</div>
</div>
</body>
</html>
选项卡插件样式:
* {
margin:;
padding:;
}
body {
font-size: 14px;
font-family: Tahoma, Verdana,"Microsoft Yahei";
}
a{
text-decoration: none;
color:#000;
}
ul,li{
list-style-type: none;
}
img {
border:none;
}
.main {
width:960px;
margin:20px auto;
}
.tab{
margin: 0 auto 20px;
}
.tab1 .tab-nav{
margin-bottom:8px;
}
.tab .tab-nav {
overflow:hidden;
}
.tab1 .tab-nav .active{
border-bottom:1px solid #000;
}
.tab1 .tab-nav li {
float:left;
margin:0 10px;
}
.tab1 .tab-nav li a {
line-height:40px;
display:block;
}
.tab1 .tab-content {
height:250px;
overflow:hidden;
}
.tab1 .tab-content p {
height:250px;
background:#eee;
}
最终效果:
[js插件开发教程]原生js仿jquery架构扩展开发选项卡插件的更多相关文章
- [js插件开发教程]实现一个比较完整的开源级选项卡插件
在这篇文章中,我实现了一个基本的选项卡功能:请猛击后面的链接>> [js插件开发教程]原生js仿jquery架构扩展开发选项卡插件. 还缺少两个常用的切换(自动切换与透明度渐变),当然 ...
- [js插件开发教程]一步步开发一个可以定制配置的隔行变色小插件
隔行变色功能,不用js,直接用css伪类就可以做,这个实例可以作为js插件开发很好的入门级实例.本文实现的隔行变色包括以下功能: 1,支持2种常用结构共存( div元素 和 表格类型 ) 2,一个页面 ...
- js 小工具-- 原生 js 去除空格
// 原生js 去除字符串空格 <script type="text/javascript"> String.prototype.trim = function (){ ...
- 编写一个jQuery的扩展方法(插件)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- [js插件开发教程]定制一个手风琴插件(accordion)
本文带来一个垂直方向的手风琴插件开发,可以定制的功能如下: contentClass : 'panel', //面板样式navClass : 'nav', //导航样式activeClass : 'a ...
- js中的原生Ajax和JQuery中的Ajax
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). js中的Ajax: 参数介绍: open(String method,Str ...
- js设置cookie(原生js)
cookie 与 session 是网页开发中常用的信息存储方式.Cookie是在客户端开辟的一块可存储用户信息的地方:Session是在服务器内存中开辟的一块存储用户信息的地方. JavaScrip ...
- 【JS新手教程】JS获取当前星期几的几种方法
该文通过获取星期几的几种方法,介绍JS里的数组,判断,和字符串截取,可以当作新手教程看,小白也看的懂.获取星期几,可通过Date()对象的getDay()获取,获取的是一个数字,对应的是0,1,2,3 ...
- 无限循环轮播图之JS部分(原生JS)
JS逻辑与框架调用, <script type="text/javascript"> var oBox = document.getElementById('box') ...
随机推荐
- 201521123065《Java程序设计》第六周学习总结
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 1.2 可选:使用常规方法总结其他上课内容. 1.publ ...
- 201521123006 《Java程序设计》第1周学习总结
1. 本章学习总结 (1)java在使用的过程中可以发现其本身有着许多为了节约资源而作的设计,而java根据其应用领域分为了三大平台:Java SE.Java ME与Java EE.在本周的学习中我们 ...
- 201521123057 《Java程序设计》第11周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) ...
- 用List传递学生信息
集合在程序开发中经常用到,例如,在业务方法中将学生信息.商品信息等存储到集合中,然后作为方法的返回值返回给调用者,以此传递大量的有序数据. 本实例将使用List集合在方法之间传递学生的信息.实例效果如 ...
- Python学习笔记011_模块_标准库_第三方库的安装
容器 -> 数据的封装 函数 -> 语句的封装 类 -> 方法和属性的封装 模块 -> 模块就是程序 , 保存每个.py文件 # 创建了一个hello.py的文件,它的内容如下 ...
- hadoop2.x的变化
HDFS Federation(HDFS联邦) HDFS有两个主要层: Namespace 由目录.文件和块组成:支持所有命名空间对文件和目录的操作. Block Storage Service 由B ...
- JavaScript中的位置屬性
屏幕中的位置(直接使用,無需前綴): screenLeft.screenTop:除了火狐都支持 screenX.screenY: 窗口的大小(谷歌的inner=outer,直接使用,無需前綴): in ...
- js 倒计时(服务器时间同步)
首先说一下,为什么要服务器时间同步, 因为服务器时间和本地电脑时间存在一定的时间差.有些对时效性要求非常高的应用,例如时时彩开奖,是不能容忍这种时间差存在的. 方案1:每次倒计时去服务端请求时间 // ...
- mybatis错误——java.io.IOException: Could not find resource com/xxx/xxxMapper.xml
在学习Mybatis的时候,参考网上的教程进行简单demo的搭建,配置的没有问题,然后出现了下面的错误! Exception in thread "main" java.lang. ...
- 批处理之 for/f 详解
含有/F的for格式:FOR /F ["options"] %%i IN (file) DO command FOR /F ["options"] %%i IN ...