km之路--008 jquery 001 插件开发 规范

命名规范

通常情况下采用下面的模式进行命名:

jquery.pluginName.js

min版则采用与之类似的命名规划,并添加一个min标记:

jquery.pluginName.min.js

扩展jquery的三种方法

1. 通过一个简单的、jquery函数prototype属性的别名(jquery.fn)进行扩展

这种方法其是实添加一个函数,例如each、ajax这样的
2. 使用jquery.extend()方法

这是平常使用的方式
3. 使用jquery ui widget factory进行扩展

这是jquery ui中的,不过它可以脱离jquery ui运行。这种方法可以创建有状态的插件。

之前写的折叠面板

css

 1 .km-accdion{
 2     width: 100%;
 3     overflow: hidden;
 4 }
 5 
 6 .km-accdion ul{
 7     margin: 0;
 8     padding: 0;
 9 }
10 
11 .km-accdion ul li{
12     margin: 0;
13     padding: 0;
14     list-style: none;
15 }
16 
17 .km-accdion-menu{
18     border-top: 1px solid #cccccc;
19     border-bottom: 1px solid #cccccc;
20 }
21 
22 .km-accdion-menu a{
23     display: block;
24     color: #555;
25     text-decoration: none;
26     background-color: #aaaaaa;
27     padding: .5em 1em;
28 }
29 
30 .km-accdion-menu a:hover{
31     color: white;
32 }
33 
34 .km-accdion-menu-item{
35     display: none;
36 }
37 
38 .km-accdion-menu-item a{
39     display: block;
40     color: #555;
41     text-decoration: none;
42     background-color: #dddddd;
43     padding: .5em 1em;
44     border-width: 1px;
45     border-color: transparent;
46     border-top-style: solid;
47     background-clip: padding-box;
48 }
49 
50 .km-accdion-menu-item a:hover{
51     color: #fff;
52     background-color: #cccccc;
53 }
54 
55 .km-accdion-menu-item-show{
56     display: block !important;
57 }
58 
59 .km-accdion-menu-item-show a{
60     display: block;
61     color: #555;
62     text-decoration: none;
63     background-color: #dddddd;
64     padding: .5em 1em;
65 }
66 
67 .km-accdion-menu-item-show a:hover{
68     color: #fff;
69     background-color: #cccccc;
70 }

js

 1 /**
 2  * 手风琴插件
 3  * TODO 多层嵌套
 4  * TODO 前面加小图标
 5  * TODO 去除对 reset.css 的依赖
 6  */
 7 ;(function ($) {
 8     'use strict';
 9 
10     /**
11      * 默认配置
12      * event : 触发手风琴切换的事件名称
13      * onlyOneMenuItem : 是否只显示一个菜单,true 表示只显示一个,false 表示每个菜单都可单独打开与关闭
14      * @type {{event: string, onlyOneMenuItem: boolean}}
15      */
16     var defaultOption = {
17         event: 'click',
18         onlyOneMenuItem : true
19     };
20 
21     var accdionClass = {
22         accdionItem : '.km-accdion-item',
23         accdionItemStr : 'km-accdion-item',
24 
25         accdionMenu : '.km-accdion-menu',
26         accdionMenuStr : 'km-accdion-menu',
27 
28         accdionMenuItem : '.km-accdion-menu-item',
29         accdionMenuItemStr : 'km-accdion-menu-item'
30     };
31 
32     /**
33      * 隐藏其它菜单
34      * @param currentItem 当前所在的 $('.km-accdion-item') 对象
35      */
36     function hideOtherMenuItem( currentItem ){
37         /**
38          *
39          * 其它菜单隐藏
40          * 思路:
41          * 1. 每次点击当前item的时候为其设置一个唯一ID,值为 currentMenuItemId + 时间戳 + 一个随机数,如:currentMenuItemId1513119262000578
42          * 2. 通过 $.siblings方法查找当前插件实例中的每个item,并加上not过滤,过滤值为当前item的id
43          * 3. 通过slideUp方法隐藏
44          *
45          */
46         var currentItemId = 'currentMenuItemId' + Date.parse(new Date().toDateString()) + Math.round(Math.random() * 10000);
47         currentItem.attr('id',currentItemId);
48         currentItem.siblings(accdionClass.accdionItem).not('#'+currentItemId).find(accdionClass.accdionMenuItem).slideUp(500);
49     }
50 
51     $.fn.kmaccdion = function (options) {
52 
53         var option = $.extend({},defaultOption,options);
54 
55         return this.each(function () {
56             var self = $(this);
57 
58             self.find(accdionClass.accdionItem).each(function () {
59                 var currentItem = $(this);
60                 currentItem.find(accdionClass.accdionMenu).on(option.event, function () {
61                     // 当前菜单的显示与隐藏
62                     var currentMenuItem = $(this);
63                     currentMenuItem.next(accdionClass.accdionMenuItem).slideToggle(300);
64 
65                     if( option.onlyOneMenuItem ){
66                         hideOtherMenuItem(currentItem);
67                     }
68 
69                 });
70             });
71 
72         });
73     };
74 })(jQuery);

引用

 1 <!-- category -->
 2 <div id="category-container">
 3     <div class="km-accdion">
 4         <div class="km-accdion-item">
 5             <ul class="km-accdion-menu-item-show">
 6                 <li><a href="#">全部</a></li>
 7             </ul>
 8         </div>
 9         <div class="km-accdion-item">
10             <div class="km-accdion-menu">
11                 <a href="#">移动开发</a>
12             </div>
13             <ul class="km-accdion-menu-item">
14                 <li><a href="#">移动开发</a></li>
15                 <li><a href="#">Android 开发</a></li>
16                 <li><a href="#">ISO 开发</a></li>
17             </ul>
18         </div>
19         <div class="km-accdion-item">
20             <div class="km-accdion-menu">
21                 <a href="#">前端开发</a>
22             </div>
23             <ul class="km-accdion-menu-item">
24                 <li><a href="#">前端开发</a></li>
25                 <li><a href="#">HTML/CSS</a></li>
26                 <li><a href="#">JavaScript</a></li>
27                 <li><a href="#">HTML5/CSS3</a></li>
28                 <li><a href="#">ECMAScript 6</a></li>
29                 <li><a href="#">JQuery</a></li>
30             </ul>
31         </div>
32     </div>
33 </div>
34 <!-- // category -->

效果

不足

1. 面板插件绑定了面板内容的展示,无法自定义

2. 样式比较难看【好吧,以我目前的CSS水平来说,能写/抄出这样的效果已经很不错了】

3. 没有图标

4. 无法加载远程数据【这是最无法接受的

5. 不具备通用性【也是无法接受的

6. 面板切换方法太过低级

jquery插件开发最佳实践

总的来说jquery插件开发有如下最佳实践:

1. 在jquery名称空间中只为插件声明单个名称
2. 为插件中的事件和数据定义名称空间
3. 接收一个options参数以控制插件的行为
4. 为插件的默认设置提供公开的访问
5. 保护私有函数的私有性
6. 公开需要公开的函数
7. 支持链式调用

这里就不考虑metadata插件了,因为$.data已经提供了类似的功能

当然,现在只是开发折叠面板、下拉菜单、tab选项面板之类的简单插件,如果要开发datagrid等插件,我认为需要使用jquery ui widget factory。

一个自定义事件的例子

这个例子实现的功能很简单,

在一个div中有一个按钮

div默认有边框和padding

单击按钮可以改变边框颜色或者去掉padding

当边框改变之后,触发自定义事件【重难点】

js

  1 ;(function ($, window, document, undefined) {
  2 
  3     /**
  4      * 插件的私有方法
  5      * 初始化
  6      * @param jq jquery 对象,和你使用$('#one')获得的对象是一样的
  7      */
  8     function init(jq) {
  9         // 初始化步骤:
 10         // 1. 初始化插件样式,这里就不写那么多了
 11         console.log('私有方法:init');
 12 
 13         // 2. 自定义事件
 14         // 绑定事件,我这里是直接绑定在插件本身上面
 15         jq.on('onBorderChanged.kmAccordion', jq.config.onBorderChanged);
 16 
 17         // 3. 绑定单击事件逻辑,实现点击按钮,改变padding和border
 18         jq.find('button').click(function () {
 19             var text = jq.find('button').text();
 20             // 私有方法调用公有方法
 21             jq.kmAccordion('changeBorder',text);
 22         });
 23     }
 24 
 25     function sayNo() {
 26         console.log('私有方法:sayNo');
 27     }
 28 
 29     /**
 30      * 插件实现代码
 31      * @param options 如果是json对象,则创建[初始化]插件,如果是字符串,则用来调用插件的公开方法
 32      * @param param 当前options是字符串时,代表传递给插件公开方法的参数。当然,你可以不传
 33      * @returns {*}
 34      */
 35     $.fn.kmAccordion = function (options, param) {
 36         // console.log(this);
 37         // 如果是方法调用
 38         if (typeof options === 'string') {
 39             return $.fn.kmAccordion.methods[options](this, param);
 40         }
 41 
 42         // 获得配置,这里为了得到用户的配置项,覆盖默认配置项,并保存到当前jquery插件实例中
 43         var _opts = $.extend({}, $.fn.kmAccordion.defaults, options);
 44         var jq = this;
 45         jq.config = _opts;
 46 
 47         // 链式调用
 48         return this.each(function () {
 49             // console.log(this);
 50             // 调用私有方法,初始化插件
 51             init(jq);
 52         });
 53     };
 54 
 55 
 56     /**
 57      * 插件的公开方法
 58      */
 59     $.fn.kmAccordion.methods = {
 60         changeBorder: function (jq, text) {
 61             // 公有方法可以相互调用
 62             jq.kmAccordion('sayHello');
 63 
 64             // 公有方法调用私有方法,但是对插件外部来说,私有方法是不可见的
 65             sayNo();
 66 
 67             // 实现逻辑
 68             jq.css({'border-color':jq.config.color});
 69             if( jq.config.clearPadding ){
 70                 jq.css({'padding':'0'});
 71             }
 72             console.log('按钮文本:'+text);
 73 
 74             // 触发事件
 75             jq.config.onBorderChanged.call(jq, jq.css('border-color'));
 76 
 77             // 返回jquery对象,支持链式调用
 78             return jq;
 79         },
 80         sayHello : function(jq){
 81               console.log('hello');
 82               return jq;
 83         },
 84         options: function (jq) {
 85             // 这个就不需要支持链式调用了
 86             return jq.config;
 87         }
 88     };
 89 
 90 
 91     /**
 92      * 插件的默认配置
 93      */
 94     $.fn.kmAccordion.defaults = {
 95         // 属性
 96         clearPadding: true,
 97         color: 'blue',
 98 
 99         /**
100          * 自定义事件
101          * @param color 事件触发时的参数
102          */
103         onBorderChanged: function (color) {
104             console.log('默认事件实现,当然,你也可以不实现,留空:' + color);
105         }
106     };
107 })(jQuery, window, document);

调用

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <style>
 7         div{
 8             border: 1px solid red;
 9             padding: 20px;
10             float: left;
11             margin: 20px;
12         }
13     </style>
14 </head>
15 <body>
16 <div id="one">
17     <button>第一个按钮</button>
18 </div>
19 <div id="two">
20     <button>第二个按钮</button>
21 </div>
22 
23 <button id="btnone">调用第一个插件的方法</button>
24 <button id="btntwo">调用第二个插件的方法</button>
25 
26 
27 
28 <script type="text/javascript" charset="UTF-8" src="./external/jquery.min.js"></script>
29 <script type="text/javascript" charset="UTF-8" src="one.js"></script>
30 <script type="text/javascript" charset="UTF-8">
31     $(function () {
32         // 实例化插件,改变一下默认配置
33         var one = $('#one').kmAccordion({
34             clearPadding:false,
35             color : 'black',
36             onBorderChanged : function (color) {
37                 console.log('自定义事件:'+color);
38             }
39         });
40         // 实例化插件,使用默认配置
41         var two = $('#two').kmAccordion();
42 
43         $('#btnone').click(function () {
44             console.log('外部调用 公开方法 1');
45             // 调用插件的方法,同时会触发自定义事件
46             one.kmAccordion('changeBorder',one.find('button').text());
47         });
48 
49         $('#btntwo').click(function () {
50             console.log('外部调用 公开方法 2');
51             // 这个也调用一下
52             two.kmAccordion('changeBorder',two.find('button').text());
53         });
54 
55     });
56 </script>
57 </body>
58 </html>

效果


默认运行效果


单击第一个div中的按钮


刷新页面,单击第二个div中的按钮


刷新页面,单击:《调用第一个插件的方法》按钮


刷新页面,单击:《调用第二个插件的方法》按钮

可以看到效果还是不错的。

注意事项

要时刻注意this的指向

把36行和49行注释打开,刷新页面,就会看到原因

上面例子的演变流程

基于MVC的JavaScript Web富应用开发

 KM项目插件体系规划

N-2

研究 jquery ui 源码

N-1

研究Bootstrap js组件源码

终极目标

基于es5/6构建KM项目前端JS UI库

khl
原文地址:https://www.cnblogs.com/khlbat/p/8176986.html