[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') ...
随机推荐
- 5th-个人总结(Alpha阶段)
一. 总结自己的Alpha过程 1.团队的整体情况 在团队中这次担任队长的职务. alpha阶段完成情况还算理想,大家都完成了指定的任务.但是也少不了犯错,一些需求没有划分的足够细致,后来功能完成后发 ...
- 201521123096《Java程序设计》第四周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 继承能够动态绑定,运行时能够自动的选择调用方法,十分方便. 2. 书面作业 (1)注释的应用 ...
- 201521123008《Java程序设计》第1周学习总结
本周学习总结 了解了JAVA:jdk:jre:jvm等 C语音与JAVA的部分区别: C语言全面向过程,java面向对象: C语言的代码不能跨平台,java的代码可以跨平台: C语言有指针,java没 ...
- 201521123066 《Java程序设计》第十周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 有关异常的知识点: 一段代码可能生成多种类型的异常,子类异常必须放在父类异常前面,否则会出现编译错误: 可以 ...
- 多线程:多线程设计模式(三):Master-Worker模式
Master-Worker模式是常用的并行模式之一,它的核心思想是,系统有两个进程协作工作:Master进程,负责接收和分配任务:Worker进程,负责处理子任务.当Worker进程将子任务处理完成后 ...
- Android 跳转系统选择本地视频的功能
今天在项目开发的过程中产品要求添加选择本地视频的功能,于是就翻阅和查找各种资料,进行功能的开发,但是在开发过程中发现,各种不同的品牌的手机跳转至系统选择本地视频的功能结果不太一样,所以我就对一些主流的 ...
- 市场主流5款HTML5开发框架详解
我们经常听见的前端框架是一个非常大的范词,因为前端框架都是基于JS.CSS.HTML5技术开发实现的,不过选择一个HTML5开发框架需要考虑哪些方面,首先就是需要什么样的功能,其次就是技术实现,不过当 ...
- python 浅析对return的理解
最近很忙,但是还是很认真的学习python这个东西,不是出于什么目的,只是单纯的喜欢罢了.最近学习的东西比较简单,但是也遇到了一些问题,就是比较迷惑人的问题,今天小编就在这里讲讲自己的对return的 ...
- Linux的诞生史
Linux的诞生史 目录 Multics计划--开始 自由的产物-BSD GUN计划的产生 导火索MINIX Linux的诞生 Linux的标志物 Linux的现状 Multics计划--开始. 这是 ...
- SSH复用代码最终版
web.xml文件 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="h ...