[js插件开发教程]定制一个手风琴插件(accordion)
2023-09-11 14:19:51 时间
本文带来一个垂直方向的手风琴插件开发,可以定制的功能如下:
contentClass : 'panel', //面板样式
navClass : 'nav', //导航样式
activeClass : 'active', //导航激活样式
triggerElements : '*', //触发元素
activeIndex : 0, //默认选中的元素
evType : 'click', //默认触发的事件
animate : true, //是否支持动画渐变
multiple : false //是否支持多个面板同时展开
调用方法:
$(".accordion").accordion( { animate : true, multiple : true } ); //支持多个面板同时展开, 支持动画效果
效果预览:
$(".accordion").accordion( { animate : false, multiple : true } );
这种效果就是跟选项卡一样
$(".accordion").accordion( { 'animate' : true } );
不支持多个面板,永远只有一个面板被打开
效果预览:
完整的手风琴插件代码:
html部分:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <!--作者:ghostwu(吴华)--> 5 <meta charset="UTF-8"> 6 <title></title> 7 <link rel="stylesheet" href="./css/accordion.css"/> 8 <script src="./js/accordion.js"></script> 9 <script> 10 window.onload = function(){ 11 $(".accordion").accordion( { 'animate' : true } ); 12 } 13 </script> 14 </head> 15 <body> 16 <div class="main"> 17 <div class="accordion"> 18 <div class="panel">面板1</div> 19 <div class="nav">导航1</div> 20 <div class="panel">面板2</div> 21 <div class="nav">导航2</div> 22 <div class="panel">面板3</div> 23 <div class="nav">导航3</div> 24 <div class="panel">面板4</div> 25 <div class="nav">导航4</div> 26 <div class="panel">面板5</div> 27 <div class="nav">导航5</div> 28 </div> 29 </div> 30 </body> 31 </html>
css样式部分:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 * { 2 margin: 0; 3 padding: 0; 4 } 5 body { 6 font-size: 14px; 7 font-family: Tahoma, Verdana,"Microsoft Yahei"; 8 } 9 a{ 10 text-decoration: none; 11 color:#000; 12 } 13 ul,li{ 14 list-style-type: none; 15 } 16 img { 17 border:none; 18 } 19 .main { 20 width:960px; 21 margin:20px auto; 22 } 23 24 .accordion{ 25 width:400px; 26 margin: 0 auto 10px; 27 } 28 29 .accordion .nav { 30 border-bottom: 1px dashed #0064cd; 31 } 32 .accordion .panel{ 33 height:100px; 34 background:#ccc; 35 } 36 .accordion .nav{ 37 height:30px; 38 background:#999; 39 } 40 .accordion .active{ 41 background:#ff0; 42 }
js插件部分:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * Created by ghostwu(吴华). 3 */ 4 (function(){ 5 var G = function( selectors, context ){ 6 return new G.fn.init( selectors, context ); 7 } 8 G.fn = G.prototype = { 9 length : 0, 10 constructor : G, 11 size : function(){ 12 return this.length; 13 }, 14 init : function( selector, context ){ 15 this.length = 0; 16 context = context || document; 17 if ( selector.indexOf( '#' ) == 0 ){ 18 this[0] = document.getElementById( selector.substring( 1 ) ); 19 this.length = 1; 20 }else { 21 var aNode = context.querySelectorAll( selector ); 22 for( var i = 0, len = aNode.length; i < len; i++ ) { 23 this[i] = aNode[i]; 24 } 25 this.length = len; 26 } 27 this.selector = selector; 28 this.context = context; 29 return this; 30 } 31 } 32 33 G.fn.init.prototype = G.fn; 34 G.extend = G.fn.extend = function () { 35 var i = 1, 36 len = arguments.length, 37 dst = arguments[0], 38 j; 39 if (dst.length === undefined) { 40 dst.length = 0; 41 } 42 if (i == len) { 43 dst = this; 44 i--; 45 } 46 for (; i < len; i++) { 47 for (j in arguments[i]) { 48 dst[j] = arguments[i][j]; 49 dst.length++; 50 } 51 } 52 return dst; 53 }; 54 55 function css(obj, attr, value) { 56 if (arguments.length == 3) { 57 obj.style[attr] = value; 58 } else { 59 if (obj.currentStyle) { 60 return obj.currentStyle[attr]; 61 } else { 62 return getComputedStyle(obj, false)[attr]; 63 } 64 } 65 } 66 67 function animate(obj, attr, fn) { 68 clearInterval(obj.timer); 69 var cur = 0; 70 var target = 0; 71 var speed = 0; 72 //var start = new Date().getTime();//起始时间 73 obj.timer = setInterval(function () { 74 var bFlag = true; 75 for (var key in attr) { 76 if (key == 'opacity') { 77 cur = css(obj, 'opacity') * 100; 78 } else { 79 cur = parseInt(css(obj, key)); 80 } 81 target = attr[key]; 82 speed = ( target - cur ) / 8; 83 speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); 84 console.log( cur, target ); 85 if (cur != target) { 86 bFlag = false; 87 if (key == 'opacity') { 88 obj.style.opacity = ( cur + speed ) / 100; 89 obj.style.filter = "alpha(opacity:" + ( cur + speed ) + ")"; 90 } else { 91 obj.style[key] = cur + speed + "px"; 92 } 93 } 94 } 95 if (bFlag) { 96 //var end = new Date().getTime();//结束时间 97 //console.log( '总计:', ( end - start ) ); 98 clearInterval(obj.timer); 99 fn && fn.call(obj); 100 } 101 }, 30 ); 102 } 103 104 G.fn.accordion = function( options ){ 105 options = options || {}; 106 var defaults = { 107 contentClass : 'panel', 108 navClass : 'nav', 109 activeClass : 'active', 110 triggerElements : '*', 111 activeIndex : 0, 112 evType : 'click', 113 animate : true, 114 multiple : false 115 }; 116 117 var opt = G.extend( {}, defaults, options ); 118 119 var aNavEle = this[0].querySelectorAll( "." + opt.navClass ), 120 aPanel = this[0].querySelectorAll( "." + opt.contentClass ); 121 122 var _api = {}; 123 124 var panelHeight = parseInt( css( aPanel[opt.activeIndex], 'height' ) ); 125 _api.setIndex = function( curIndex, effect ){ 126 if ( opt.multiple ) { 127 if ( effect ) { 128 if ( parseInt( css( aPanel[curIndex], 'height' ) ) == 0 ) { 129 aPanel[curIndex].style.display = 'block'; 130 animate( aPanel[curIndex], { 'height' : panelHeight } ); 131 }else { 132 animate( aPanel[curIndex], { 'height' : 0 }, function(){ 133 this.style.display = 'none'; 134 } ); 135 } 136 }else { 137 if ( css( aPanel[curIndex], 'display' ) == 'block' ){ 138 aPanel[curIndex].style.display = 'none'; 139 }else { 140 aPanel[curIndex].style.display = 'block'; 141 } 142 if ( aNavEle[curIndex].classList.contains( 'active' ) ) { 143 aNavEle[curIndex].classList.remove( 'active' ); 144 }else { 145 aNavEle[curIndex].classList.add( 'active' ); 146 } 147 } 148 }else { 149 if ( effect ) { 150 for ( var i = 0; i < aPanel.length; i++ ) { 151 if( i != curIndex ) { 152 if ( aPanel[i].style.display == 'block' ){ 153 animate( aPanel[i], { 'height' : 0 }, function(){ 154 this.style.display = 'none'; 155 } ); 156 }else{ 157 aPanel[i].style.display = 'none'; 158 } 159 }else { 160 aPanel[curIndex].style.display = 'block'; 161 animate( aPanel[curIndex], { 'height' : panelHeight } ); 162 } 163 } 164 }else { 165 for ( var i = 0 ; i < aPanel.length; i++ ){ 166 aPanel[i].style.display = 'none'; 167 aNavEle[i].classList.remove( 'active' ); 168 } 169 aPanel[curIndex].style.display = 'block'; 170 aNavEle[curIndex].classList.add( 'active' ); 171 } 172 } 173 }; 174 175 _api.setIndex( opt.activeIndex, opt.animate ); 176 177 for( var i = 0 ; i < aNavEle.length; i++ ) { 178 aNavEle[i].index = i; 179 aNavEle[i].addEventListener( opt.evType, function(){ 180 _api.setIndex( this.index, opt.animate ); 181 }, false ); 182 } 183 return this; 184 } 185 186 var $ = function( selectors, context ){ 187 return G( selectors, context ); 188 } 189 window.$ = $; 190 })();
相关文章
- js api 实现钉钉免登
- h5 录音 自动生成proto Js语句 UglifyJS-- 对你的js做了什么 【原码笔记】-- protobuf.js 与 Long.js 【微信开发】-- 发送模板消息 能编程与会编程 vue2入坑随记(二) -- 自定义动态组件 微信上传图片
- JS监听不到被操作后dom的事件,js动态生成的DOM绑定事件失效,解决方案
- 【JavaScript】js中Dom操作增删改查技巧大全(示例)
- 【JS】js创建Object对象和构造函数的多种方法(综合示例)
- 微信小程序 - 父组件调用子组件的函数方法(像 Vue.js 中 ref 属性一样,直接 this.$refs.xx 获取子组件数据和方法)详细教程示例代码
- HTML、CSS、JS对unicode字符的不同处理
- 《Node.js入门经典》一2.11 测验
- 《Ember.js实战》——2.6 Ember.js实现各层间数据同步
- => js 中箭头函数使用总结
- 有趣的HTML实例(十三) 咖啡选择(css+js)
- [js高手之路]html5 canvas教程 - 1px问题以及绘制坐标系网格
- [js高手之路] html5 canvas系列教程 - 像素操作(反色,黑白,亮度,复古,蒙版,透明)
- [js高手之路] html5 canvas系列教程 - arc绘制曲线图形(曲线,弧线,圆形)
- [js高手之路]深入浅出webpack教程系列5-插件使用之html-webpack-plugin配置(中)
- [js高手之路] es6系列教程 - 箭头函数详解
- js原生获取某元素的属性的兼容性方法
- 【cocos2d-js官方文档】五、Cocos2d-JS v3.0的新Action API
- 10天掌握webpack 4.0 JS 篇 (1)
- JQuery/JS插件 linq.js 获取所有选中行的Id
- JQuery/JS插件 linq.js 入门
- Node.js querystring模块