大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ Tab功能扩展完结版)

一,开篇分析

Hi,大家好!大熊君又和大家见面了,还记得上一篇文章吗。主要讲述了一个“Tab”插件是如何组织代码以及实现的”,以及过程化设计与面向对象思想设计相结合的方式是

如何设计一个插件的,两种方式各有利弊取长补短,本系列文章是以学习为导向的,具体场景大家自己定夺使用方式。在从这篇文章中,我们还是以那个“Tab”实例为主,

继续扩展相关功能。嘿嘿嘿,废话少说,进入正题。直接上实际效果图:

  

大家看到了吧,增加了一个新的功能,如果我们在初始化时,我们的模块配置信息项目的条目数大于我们指定的,那么就会显示在“更多模块”

操作项的隐藏列表中,我们的初始化参数配置也从新做了调整比如多了一个“displayMax”指定初始化时的条目数,还有一个项目属性,“status”

在初始化时也去掉了不需要配置了,在程序中动态生成配置,增加了程序的灵活性,下面就具体分析一下吧。

 

(二),实例分析

(1),首先确定这个插件做什么事。下面看一下插件的调用方式,以及配置参数说明。如下代码:

  

复制代码
 1 {
 2     buttonText : "添加模块" ,
 3     result : [ 
 4         {
 5             text : "向导提示" ,
 6             url : "help.html" ,
 7             showClose : "0"
 8         } ,
 9         {
10             text : "学生信息" ,
11             url : "info.html" ,
12             showClose : "1"
13         } ,
14         {
15             text : "学生分类" ,
16             url : "category.html" ,
17             showClose : "1"
18         } ,
19         {
20             text : "大熊君{{bb}}" ,
21             url : "bb.html" ,
22             showClose : "1"
23         } ,
24         {
25             text : "Beta测试模块" ,
26             url : "test.html" ,
27             showClose : "1"
28         } ,
29         {
30             text : "三胖子" ,
31             url : "help.html" ,
32             showClose : "1"
33         } ,
34         {
35             text : "四秃子" ,
36             url : "help.html" ,
37             showClose : "1"
38         }
39     ] ,
40     displayMax : 5 // 最多显示项目
41 }    
复制代码

 

  

“bigbear.ui.createTab”里面包含两个参数,第一个是dom节点对象,第二个是插件参数选项,"buttonText "代表“Tab“插件中,操作按钮的文字描述。

”result“是一个数组,里面包含的是选项卡项目的属性,包括文字描述,点击选项卡项目时做请求使用的url,”showClose“代表选项卡的选项是否显示关闭按钮。

“status”在初始化时也去掉了不需要配置了,在程序中动态生成配置。可能会有关闭状态,分别表示为:1-默认显示,0-关闭状态,2-超过默认的条目数。

 

(2),功能分步骤介绍

1---,通过可选参数,初始化插件:

  

复制代码
 1 $(function(){
 2     bigbear.ui.createTab($("#tab"),{
 3         buttonText : "添加模块" ,
 4         result : [ 
 5             {
 6                 text : "向导提示" ,
 7                 url : "help.html" ,
 8                 showClose : "0"
 9             } ,
10             {
11                 text : "学生信息" ,
12                 url : "info.html" ,
13                 showClose : "1"
14             } ,
15             {
16                 text : "学生分类" ,
17                 url : "category.html" ,
18                 showClose : "1"
19             } ,
20             {
21                 text : "大熊君{{bb}}" ,
22                 url : "bb.html" ,
23                 showClose : "1"
24             } ,
25             {
26                 text : "Beta测试模块" ,
27                 url : "test.html" ,
28                 showClose : "1"
29             } ,
30             {
31                 text : "三胖子" ,
32                 url : "help.html" ,
33                 showClose : "1"
34             } ,
35             {
36                 text : "四秃子" ,
37                 url : "help.html" ,
38                 showClose : "1"
39             }
40         ] ,
41         displayMax : 5 // 最多显示项目
42     }) ;
43 }) ;            
复制代码

 

2---,渲染并且完成时间绑定以及相关的业务逻辑,比如初始化时条目数量验证。

  

复制代码
 1 tabProto.init = function(){
 2     if(this._isEmptyResult()){
 3         this._setContent("暂无任何模块!") ;
 4     }
 5     var that = this ;
 6     this.getElem().find(".title .adder")
 7     .text("+" + this.getOpts()["buttonText"])
 8     .on("click",function(){
 9         that.getElem().find(".console-panel").slideToggle(function(){
10             that._renderConsolePanel("0") ;
11         }) ;
12     }) ;
13     $.each(this.getOpts()["result"],function(i,item){
14         if(that._isDisplayMax(i + 1)){
15             that._saveOrUpdateStatus(item,"1") ;
16         }
17         else{
18             that._saveOrUpdateStatus(item,"2") ;
19         }
20         that._render(item) ;
21     }) ;
22     if(!that._isDisplayMax(this.getOpts()["result"].length)){
23         this.getElem().find(".title .more-mod").fadeIn(function(){
24             $(this).find(".tag").on("click",function(){
25                 var root = $(this).next() ;
26                 root.empty() ;
27                 $.each(that._getItemListByStatus("2"),function(i,data){
28                     $("<div></div>").text(data["text"])
29                     .on("click",function(){
30                         if(that._getItemListByStatus("1").length < that.getOpts()["displayMax"]){
31                             that.getElem().find(".title .items div").eq(data["index"]).fadeIn(function(){
32                                 that._saveOrUpdateStatus(data,"1") ;
33                             }) ;
34                         }
35                         else{
36                             alert("不能添加任何模块,目前已经是最大数量!") ;
37                         }
38                     })
39                     .appendTo(root) ;
40                 }) ;
41                 root.toggle() ;
42             }) ;
43             
44         });
45     }
46     this.getElem().find(".title .items div")
47     .eq(0)
48     .trigger("click") ; // 假定是必须有一项,否则插件意义就不大了!
49 } ;
复制代码

 

3---,选项卡切换以及数据内容渲染操作。

  

1 tabProto._setCurrent = function(index){
2     var items = this.getElem().find(".title .items div").removeClass("active") ;
3     items.eq(index).addClass("active") ;
4     var contents = this.getElem().find(".content .c").hide() ;
5     contents.eq(index).show() ;
6 } ;    

 

复制代码
1 item.on("click",function(){
2     that._setCurrent($(this).index()) ;
3     that._getContent(data["url"]).done(function(result){
4         that._setContent(result) ;
5     })
6     .fail(function(){
7         throw new Error("Net Error !") ;
8     });
9 })
复制代码

 

 

1 tabProto._setContent = function(html){
2     this.getElem().find(".content").html(html) ;
3 } ;
4 tabProto._getContent = function(url){
5     return $.ajax({
6         url : url
7     }) ;
8 } ;

 

4---,核心的辅助数据操作方法,不涉及dom。

复制代码
 1 /* update time 2015 1/26 15:36 */ 
 2 tabProto._isDisplayMax = function(size){
 3     var displayMax = this.getOpts()["displayMax"] || 5 ;
 4     return (size <= displayMax) ? true : false ;
 5 } ;
 6 tabProto._isEmptyResult = function(){
 7     if(!this.getOpts()["result"].length){
 8         return false ;
 9     }
10     return true ;
11 } ;
12 tabProto._saveOrUpdateStatus = function(item,status){
13     item["status"] = status ;
14 } ;
15 tabProto._getItemListByStatus = function(status){
16     var list = [] ;
17     var result = this.getOpts()["result"] ;
18     $.each(result,function(i,item){
19         if(status == item["status"]){
20             list.push(item) ;
21         }
22     }) ;
23     return list ;
24 } ;
25 tabProto._getStatusByIndex = function(index){
26     var status = null ;
27     var result = this.getOpts()["result"] ;
28     $.each(result,function(i,item){
29         if(index == item["index"]){
30             status = item["status"] ;
31         }
32     }) ;
33     return status ;
34 } ;
复制代码

 

(三),完整代码以供学习,本代码已经过测试,包括目录结构以及相关的文件。

 1,html

复制代码
 1 <body>
 2     <div class="dxj-ui-hd">
 3         大熊君{{bb}} - DXJ UI ------ Tab
 4     </div>
 5     <div class="dxj-ui-bd">
 6         <div id="tab">
 7             <div class="title">
 8                 <div class="adder">
 9                     + 添加学生信息
10                 </div>
11                 <div class="items">
12                     <!--<div><span class="del">X</span>欢迎页</div>
13                     <div><span class="del">X</span>用户管理</div>
14                     <div><span class="del">X</span>Bigbear</div>-->
15                 </div>
16                 <div class="more-mod">
17                     <div class="tag">更多模块</div>
18                     <div class="mods">
19                         
20                     </div>
21                 </div>
22             </div>
23             <div class="console-panel">
24             </div>
25             <div class="content">
26                 <!--<div class="c">
27                 
28                     <div class="input-content"><span>姓名:</span><input type="text" /></div>
29                     <div class="input-content"><span>备注:</span><textarea></textarea></div>
30                 
31                 </div>    <div class="input-content"><input type="button" value="保存" /></div>
32                 -->
33             </div>
34         </div>
35     </div>
36 </body>
复制代码

 

2,css

  

复制代码
  1 .dxj-ui-hd {
  2     padding:0px ;
  3     margin : 0 auto;
  4     margin-top:30px;
  5     width:780px;
  6     height:60px;
  7     line-height: 60px;
  8     background: #3385ff;
  9     color:#fff;
 10     font-family: "微软雅黑" ;
 11     font-size: 28px;
 12     text-align: center;
 13     font-weight:bold;
 14 }
 15 .dxj-ui-bd {
 16     padding:0px ;
 17     margin : 0 auto;
 18     width:778px;
 19     padding-top : 30px ;
 20     padding-bottom : 30px ;
 21     overflow: hidden;
 22     border:1px solid #3385ff;
 23 }
 24 .dxj-ui-bd #tab {
 25     padding:0px ;
 26     margin : 0 auto;
 27     width:720px;
 28     overflow: hidden;
 29     position:relative;
 30 }
 31 .dxj-ui-bd #tab .title {
 32     width:720px;
 33     overflow: hidden;
 34     border-bottom:2px solid #3385ff;
 35 }
 36 .dxj-ui-bd #tab .title .adder {
 37     width:160px;
 38     height:32px;
 39     line-height: 32px;
 40     background: #DC143C;
 41     color:#fff;
 42     font-family: "微软雅黑" ;
 43     font-size: 14px;
 44     text-align: center;
 45     font-weight:bold;
 46     float : left;
 47     cursor:pointer;
 48 }
 49 .dxj-ui-bd #tab .title .more-mod {
 50     overflow:hidden;
 51     border:1px solid #DC143C;
 52     width:70px;
 53     position:absolute;
 54     right:0;
 55     margin-right:6px;
 56     display:none;
 57 }
 58 .dxj-ui-bd #tab .title .more-mod .tag{
 59     height:32px;
 60     line-height:32px;
 61     width:70px;
 62     background: #DC143C;
 63     color:#fff;
 64     font-family: arial ;
 65     font-size: 12px;
 66     text-align: center;
 67     cursor:pointer;
 68 }
 69 .dxj-ui-bd #tab .title .more-mod .mods {
 70     overflow:hidden;
 71     width:70px;
 72     display:none;
 73 }
 74 .dxj-ui-bd #tab .title .more-mod .mods div {
 75     height:24px;
 76     line-height:24px;
 77     width:62px;
 78     font-family: arial ;
 79     font-size: 12px;
 80     cursor:pointer;
 81     padding-left:10px;
 82 }
 83 .dxj-ui-bd #tab .title .items {
 84     height:32px;
 85 
 86     width:480px;
 87     overflow: hidden;
 88     float : left;
 89 }
 90 .dxj-ui-bd #tab .title .items div {
 91     padding:0px;
 92     margin-left:10px;
 93     width:84px;
 94     height:32px;
 95     line-height: 32px;
 96     background: #3385ff;
 97     color:#fff;
 98     font-family: arial ;
 99     font-size: 12px;
100     text-align: center;
101     position:relative;
102     float : left;
103     cursor:pointer;
104 }
105 .dxj-ui-bd #tab .title .items div span.del {
106     width:16px;
107     height:16px;
108     line-height: 16px;
109     display:block;
110     background: #DC143C;
111     position:absolute;
112     right:0 ;
113     top:0;
114     cursor:pointer;
115 }
116 .dxj-ui-bd #tab .content {
117     width:716px;
118     padding-top:30px;
119     overflow: hidden;
120     border:2px solid #3385ff;
121     border-top:0px;
122     min-height:130px;
123     text-align:center;
124 }
125 .dxj-ui-bd #tab .content table {
126     margin : 0 auto ;
127 }
128 .dxj-ui-bd #tab .content div.c {
129     padding-top : 20px ;
130     padding-left:20px;
131     background:#eee;
132     height:140px;
133 }
134 .dxj-ui-bd #tab .content div.c .input-content {
135     margin-top : 10px ;
136     font-family: arial ;
137     font-size: 12px;
138 }
139 .dxj-ui-bd #tab .console-panel {
140     width:716px;
141     padding-top:20px;
142     padding-bottom:20px;
143     overflow: hidden;
144     border:2px solid #3385ff;
145     border-top:0px;
146     border-bottom:2px solid #3385ff;
147     background:#fff;
148     display:none;
149 }
150 
151 .active {
152     font-weight:bold ;
153 }
复制代码

 

3,bigbear.js

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
(function($){
    var win = window ;
    var bb = win.bigbear = win.bigbear || {
        ui : {}
    } ;
    var ui = bb.ui = {} ;
    var Tab = function(elem,opts){
        this.elem = elem ;
        this.opts = opts ;
    } ;
    var tabProto = Tab.prototype ;
    /* update time 2015 1/26 15:36 */
    tabProto._isDisplayMax = function(size){
        var displayMax = this.getOpts()["displayMax"] || 5 ;
        return (size <= displayMax) ? true : false ;
    } ;
    tabProto._isEmptyResult = function(){
        if(!this.getOpts()["result"].length){
            return false ;
        }
        return true ;
    } ;
    tabProto._saveOrUpdateStatus = function(item,status){
        item["status"] = status ;
    } ;
    tabProto._getItemListByStatus = function(status){
        var list = [] ;
        var result = this.getOpts()["result"] ;
        $.each(result,function(i,item){
            if(status == item["status"]){
                list.push(item) ;
            }
        }) ;
        return list ;
    } ;
    tabProto._getStatusByIndex = function(index){
        var status = null ;
        var result = this.getOpts()["result"] ;
        $.each(result,function(i,item){
            if(index == item["index"]){
                status = item["status"] ;
            }
        }) ;
        return status ;
    } ;
    tabProto._renderConsolePanel = function(status){
        var that = this ;
        var root = that.getElem().find(".console-panel") ;
        this._resetConsolePanel() ;
        $.each(that._getItemListByStatus(status),function(i,item){
            var elem = $("<div style='float:left';></div>").appendTo(root) ;
            $("<input type='radio' name='addmod' />")
            .data("item",item)
            .appendTo(elem) ;
            $("<span></span>").text(item["text"]).appendTo(elem) ;
        }) ;
        if(root.find("div").size()){
            $("<input type='button' value='添加模块' style='margin-left:20px'/>")
            .on("click",function(){
                var data = root.find("input[type=radio]:checked").data("item") ;
                if(that._getItemListByStatus("1").length < that.getOpts()["displayMax"]){
                    that.getElem().find(".title .items div").eq(data["index"]).fadeIn(function(){
                        that._saveOrUpdateStatus(data,"1") ;
                    })
                    .trigger("click") ;
                }
                else{
                    that._saveOrUpdateStatus(data,"2") ;
                }
                that.getElem().find(".title .adder").trigger("click") ;
            })
            .appendTo(root) ;
        }
        else{
            root.text("暂无任何可添加的项目!") ;
        }
    } ;
    /* update time 2015 1/26 15:36 */  
    tabProto._setCurrent = function(index){
        var items = this.getElem().find(".title .items div").removeClass("active") ;
        items.eq(index).addClass("active") ;
        var contents = this.getElem().find(".content .c").hide() ;
        contents.eq(index).show() ;
    } ;
    tabProto.getElem = function(){
        return this.elem ;
    } ;
    tabProto.getOpts = function(){
        return this.opts ;
    } ;
    tabProto._resetContent = function(){
        this.getElem().find(".content").html("") ;
    } ;
    tabProto._setContent = function(html){
        this.getElem().find(".content").html(html) ;
    } ;
    tabProto._getContent = function(url){
        return $.ajax({
            url : url
        }) ;
    } ;
    tabProto._deleteItem = function(elem){
        var that = this ;
        this.getElem().find(".title .items div")
        .eq(elem.index())
        .fadeOut(function(){
            that._resetContent() ;
            that._saveOrUpdateStatus(elem.data("item"),"0") ;
            that._triggerItem(elem.index() + 1) ;
        }) ;
    } ;
    tabProto._triggerItem = function(next){
        var nextStatus = this._getStatusByIndex(next) ;
        var items = this.getElem().find(".title .items div") ;
        next = items.eq(next) ;
        if(next.size() && "1" == nextStatus){ //后继dom节点存在
            next.trigger("click") ;
        }
        else{
            items.eq(0).trigger("click") ;
        }
    } ;
    tabProto._resetConsolePanel = function(){
        this.getElem().find(".console-panel").empty() ;
    } ;
    tabProto.init = function(){
        if(this._isEmptyResult()){
            this._setContent("暂无任何模块!") ;
        }
        var that = this ;
        this.getElem().find(".title .adder")
        .text("+" + this.getOpts()["buttonText"])
        .on("click",function(){
            that.getElem().find(".console-panel").slideToggle(function(){
                that._renderConsolePanel("0") ;
            }) ;
        }) ;
        $.each(this.getOpts()["result"],function(i,item){
            if(that._isDisplayMax(i + 1)){
                that._saveOrUpdateStatus(item,"1") ;
            }
            else{
                that._saveOrUpdateStatus(item,"2") ;
            }
            that._render(item) ;
        }) ;
        if(!that._isDisplayMax(this.getOpts()["result"].length)){
            this.getElem().find(".title .more-mod").fadeIn(function(){
                $(this).find(".tag").on("click",function(){
                    var root = $(this).next() ;
                    root.empty() ;
                    $.each(that._getItemListByStatus("2"),function(i,data){
                        $("<div></div>").text(data["text"])
                        .on("click",function(){
                            if(that._getItemListByStatus("1").length < that.getOpts()["displayMax"]){
                                that.getElem().find(".title .items div").eq(data["index"]).fadeIn(function(){
                                    that._saveOrUpdateStatus(data,"1") ;
                                }) ;
                            }
                            else{
                                alert("不能添加任何模块,目前已经是最大数量!") ;
                            }
                        })
                        .appendTo(root) ;
                    }) ;
                    root.toggle() ;
                }) ;
                 
            });
        }
        this.getElem().find(".title .items div")
        .eq(0)
        .trigger("click") ; // 假定是必须有一项,否则插件意义就不大了!
    } ;
    tabProto._render = function(data){
        var that = this ;
        var item = $("<div></div>").text(data["text"]).appendTo(this.getElem().find(".title .items")) ;
        data["index"] = item.index() ;
        item.on("click",function(){
            that._setCurrent($(this).index()) ;
            that._getContent(data["url"]).done(function(result){
                that._setContent(result) ;
            })
            .fail(function(){
                throw new Error("Net Error !") ;
            });
        })
        .data("item",data) ;
        if("2" == data["status"]){
            item.hide() ;
        }
        if("1" == data["showClose"]){
            $("<span class='del'>X</span>")
            .on("click",function(){
                if(win.confirm("是否删除此项?")){
                    that._deleteItem(item) ;
                    return false ; // 阻止冒泡
                }
            })
            .appendTo(item) ;
        }
    } ;
    ui.createTab = function(elem,opts){
        var tab = new Tab(elem,opts) ;
        tab.init() ;
        return tab ;
    } ;    
})(jQuery) ;

  

(四),最后总结

  (1),面向对象的思考方式合理分析功能需求。

  (2),以类的方式来组织我们的插件逻辑。

  (3),不断重构上面的实例,如何进行合理的重构那?不要设计过度,要游刃有余,推荐的方式是过程化设计与面向对象思想设计相结合。

   

 

                   哈哈哈,本篇结束,未完待续,希望和大家多多交流够沟通,共同进步。。。。。。呼呼呼……(*^__^*)                

posted @   大熊君Bigbear  阅读(2022)  评论(11编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示