大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ Tab)

一,开篇分析

Hi,大家好!大熊君又和大家见面了,还记得前两篇文章吗。主要讲述了以“jQuery的方式如何开发插件”,以及过程化设计与面向对象思想设计相结合的方式是

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

的方式带着大家由浅入深的开发属于自己的插件库。嘿嘿嘿,废话少说,进入正题。直接上实际效果图:

  

  大家看到了吧,这是一个选项卡插件,在我们日常做那种单页应用("SPA")的时候或许会接触到,就拿今天的例子来说吧,

我们做一个基于BS结构的系统,会有若干模块组成,它们是构建系统的全部组成,通过这个插件我们可以有效地管理我们模块

的体验形式以及用户可交互性,下面就具体分析一下吧。

 

(二),实例分析

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

 1 bigbear.ui.createTab($("#tab"),{
 2     buttonText : "添加模块" ,
 3     result : [ 
 4         {
 5             text : "向导提示" ,
 6             url : "help.html" ,
 7             showClose : "0" ,
 8             status : "1"
 9         } ,
10         {
11             text : "学生信息" ,
12             url : "info.html" ,
13             showClose : "1" ,
14             status : "1"
15         } ,
16         {
17             text : "学生分类" ,
18             url : "category.html" ,
19             showClose : "1" ,
20             status : "1"
21         } ,
22         {
23             text : "大熊君{{bb}}" ,
24             url : "bb.html" ,
25             showClose : "1" ,
26             status : "1"
27         } ,
28         {
29             text : "Beta测试模块" ,
30             url : "test.html" ,
31             showClose : "1" ,
32             status : "1"
33         }
34     ]
35 }) ;

 

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

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

”status“代表选项的状态,默认为打开状态,可能会有关闭状态,分别表示为:1-打开,0-关闭。

 

(2),所涉的功能有哪些

通过可选参数,动态生成相关选项条目,如下来个例子:

  

 1 bigbear.ui.createTab($("#tab"),{
 2     buttonText : "添加模块" ,
 3     result : [ 
 4         {
 5             text : "jQuery源码分析" ,
 6             url : "help.html" ,
 7             showClose : "0" ,
 8             status : "1"
 9         } ,
10         {
11             text : "大熊君{{bb}}}" ,
12             url : "bb.html" ,
13             showClose : "1" ,
14             status : "1"
15         }
16     ]
17 }) ;

效果如下所示:

可自由添加以及删除条目选项,如下效果所示:

  

 

上图为其中一种情况,无模块的时候,会提示信息。

 

 

这是第二种情况,之前删除的可以恢复。

 

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

  (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>
17                 <div class="console-panel">
18                 
19                 </div>
20                 <div class="content">
21                     <!--<div class="c">
22                     
23                         <div class="input-content"><span>姓名:</span><input type="text" /></div>
24                         <div class="input-content"><span>备注:</span><textarea></textarea></div>
25                     
26                     </div>    <div class="input-content"><input type="button" value="保存" /></div>
27                     -->
28                 </div>
29             </div>
30         </div>
31     </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 }
 30 .dxj-ui-bd #tab .title {
 31     width:720px;
 32     overflow: hidden;
 33     border-bottom:2px solid #3385ff;
 34 }
 35 .dxj-ui-bd #tab .title .adder {
 36     width:160px;
 37     height:32px;
 38     line-height: 32px;
 39     background: #DC143C;
 40     color:#fff;
 41     font-family: "微软雅黑" ;
 42     font-size: 14px;
 43     text-align: center;
 44     font-weight:bold;
 45     float : left;
 46     cursor:pointer;
 47 }
 48 .dxj-ui-bd #tab .title .items {
 49     height:32px;
 50     margin-left:20px;
 51     width:540px;
 52     overflow: hidden;
 53     float : left;
 54 }
 55 .dxj-ui-bd #tab .title .items div {
 56     padding:0px;
 57     margin-left:10px;
 58     width:96px;
 59     height:32px;
 60     line-height: 32px;
 61     background: #3385ff;
 62     color:#fff;
 63     font-family: arial ;
 64     font-size: 12px;
 65     text-align: center;
 66     position:relative;
 67     float : left;
 68     cursor:pointer;
 69 }
 70 .dxj-ui-bd #tab .title .items div span.del {
 71     width:16px;
 72     height:16px;
 73     line-height: 16px;
 74     display:block;
 75     background: #DC143C;
 76     position:absolute;
 77     right:0 ;
 78     top:0;
 79     cursor:pointer;
 80 }
 81 .dxj-ui-bd #tab .content {
 82     width:716px;
 83     padding-top:30px;
 84     overflow: hidden;
 85     border:2px solid #3385ff;
 86     border-top:0px;
 87     min-height:130px;
 88     text-align:center;
 89 }
 90 .dxj-ui-bd #tab .content table {
 91     margin : 0 auto ;
 92 }
 93 .dxj-ui-bd #tab .content div.c {
 94     padding-top : 20px ;
 95     padding-left:20px;
 96     background:#eee;
 97     height:140px;
 98 }
 99 .dxj-ui-bd #tab .content div.c .input-content {
100     margin-top : 10px ;
101     font-family: arial ;
102     font-size: 12px;
103 }
104 .dxj-ui-bd #tab .console-panel {
105     width:716px;
106     padding-top:20px;
107     padding-bottom:20px;
108     overflow: hidden;
109     border:2px solid #3385ff;
110     border-top:0px;
111     border-bottom:2px solid #3385ff;
112     background:#fff;
113     display:none;
114 }
115 .active {
116     font-weight:bold ;
117 }

 

(3),Js代码如下:

  

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

 

 

(四),最后总结

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

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

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

    (4),思考一下上面例子中,选项卡中的选项是否可以独立成单独的类那?比如“Item”,那么“Tab”类如何修改那?带着问题去思考吧。。。

 

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

posted @ 2015-01-24 20:34  大熊君Bigbear  阅读(3549)  评论(15编辑  收藏  举报