zl程序教程

您现在的位置是:首页 >  前端

当前栏目

JavaScript插件化开发教程(四)

2023-06-13 09:15:42 时间

一,开篇分析

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

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

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

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

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

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

(二),实例分析

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

复制代码代码如下:


{
   buttonText:"添加模块",
   result:[
       {
           text:"向导提示",
           url:"help.html",
           showClose:"0"
       },
       {
           text:"学生信息",
           url:"info.html",
           showClose:"1"
       },
       {
           text:"学生分类",
           url:"category.html",
           showClose:"1"
       },
       {
           text:"大熊君{{bb}}",
           url:"bb.html",
           showClose:"1"
       },
       {
           text:"Beta测试模块",
           url:"test.html",
           showClose:"1"
       },
       {
           text:"三胖子",
           url:"help.html",
           showClose:"1"
       },
       {
           text:"四秃子",
           url:"help.html",
           showClose:"1"
       }
   ],
   displayMax:5//最多显示项目
}   
 

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

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

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

(2),功能分步骤介绍

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

复制代码代码如下:


$(function(){
   bigbear.ui.createTab($("#tab"),{
       buttonText:"添加模块",
       result:[
           {
               text:"向导提示",
               url:"help.html",
               showClose:"0"
           },
           {
               text:"学生信息",
               url:"info.html",
               showClose:"1"
           },
           {
               text:"学生分类",
               url:"category.html",
               showClose:"1"
           },
           {
               text:"大熊君{{bb}}",
               url:"bb.html",
               showClose:"1"
           },
           {
               text:"Beta测试模块",
               url:"test.html",
               showClose:"1"
           },
           {
               text:"三胖子",
               url:"help.html",
               showClose:"1"
           },
           {
               text:"四秃子",
               url:"help.html",
               showClose:"1"
           }
       ],
       displayMax:5//最多显示项目
   });
});           

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

复制代码代码如下:
tabProto.init=function(){
   if(this._isEmptyResult()){
       this._setContent("暂无任何模块!");
   }
   varthat=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(){
               varroot=$(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.itemsdiv").eq(data["index"]).fadeIn(function(){
                               that._saveOrUpdateStatus(data,"1");
                           });
                       }
                       else{
                           alert("不能添加任何模块,目前已经是最大数量!");
                       }
                   })
                   .appendTo(root);
               });
               root.toggle();
           });
           
       });
   }
   this.getElem().find(".title.itemsdiv")
   .eq(0)
   .trigger("click");//假定是必须有一项,否则插件意义就不大了!
};

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

复制代码代码如下:
 tabProto._setCurrent=function(index){
    varitems=this.getElem().find(".title.itemsdiv").removeClass("active");
    items.eq(index).addClass("active");
    varcontents=this.getElem().find(".content.c").hide();
    contents.eq(index).show();
 };   

复制代码代码如下:
 item.on("click",function(){
    that._setCurrent($(this).index());
    that._getContent(data["url"]).done(function(result){
        that._setContent(result);
    })
    .fail(function(){
        thrownewError("NetError!");
    });
 })

 
复制代码代码如下:
 tabProto._setContent=function(html){
    this.getElem().find(".content").html(html);
 };
 tabProto._getContent=function(url){
    return$.ajax({
        url:url
    });
 };

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

复制代码代码如下:
 /*updatetime20151/2615:36*/
 tabProto._isDisplayMax=function(size){
    vardisplayMax=this.getOpts()["displayMax"]||5;
    return(size<=displayMax)?true:false;
 };
 tabProto._isEmptyResult=function(){
    if(!this.getOpts()["result"].length){
        returnfalse;
    }
    returntrue;
 };
 tabProto._saveOrUpdateStatus=function(item,status){
    item["status"]=status;
 };
 tabProto._getItemListByStatus=function(status){
    varlist=[];
    varresult=this.getOpts()["result"];
    $.each(result,function(i,item){
        if(status==item["status"]){
            list.push(item);
        }
    });
    returnlist;
 };
 tabProto._getStatusByIndex=function(index){
    varstatus=null;
    varresult=this.getOpts()["result"];
    $.each(result,function(i,item){
        if(index==item["index"]){
            status=item["status"];
        }
    });
    returnstatus;
 };

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

 1,html

复制代码代码如下:
 <body>
    <divclass="dxj-ui-hd">
        大熊君{{bb}}-DXJUI------Tab
    </div>
    <divclass="dxj-ui-bd">
        <divid="tab">
            <divclass="title">
                <divclass="adder">
                    +添加学生信息
                </div>
                <divclass="items">
                    <!--<div><spanclass="del">X</span>欢迎页</div>
                    <div><spanclass="del">X</span>用户管理</div>
                    <div><spanclass="del">X</span>Bigbear</div>-->
                </div>
                <divclass="more-mod">
                    <divclass="tag">更多模块</div>
                    <divclass="mods">
                        
                    </div>
                </div>
            </div>
            <divclass="console-panel">
            </div>
            <divclass="content">
                <!--<divclass="c">
                
                    <divclass="input-content"><span>姓名:</span><inputtype="text"/></div>
                    <divclass="input-content"><span>备注:</span><textarea></textarea></div>
                
                </div>   <divclass="input-content"><inputtype="button"value="保存"/></div>
                -->
            </div>
        </div>
    </div>
 </body>

2,css

复制代码代码如下:
 .dxj-ui-hd{
    padding:0px;
    margin:0auto;
    margin-top:30px;
    width:780px;
    height:60px;
    line-height:60px;
    background:#3385ff;
    color:#fff;
    font-family:"微软雅黑";
    font-size:28px;
    text-align:center;
    font-weight:bold;
 }
 .dxj-ui-bd{
    padding:0px;
    margin:0auto;
    width:778px;
    padding-top:30px;
    padding-bottom:30px;
    overflow:hidden;
    border:1pxsolid#3385ff;
 }
 .dxj-ui-bd#tab{
    padding:0px;
    margin:0auto;
    width:720px;
    overflow:hidden;
    position:relative;
 }
 .dxj-ui-bd#tab.title{
    width:720px;
    overflow:hidden;
    border-bottom:2pxsolid#3385ff;
 }
 .dxj-ui-bd#tab.title.adder{
    width:160px;
    height:32px;
    line-height:32px;
    background:#DC143C;
    color:#fff;
    font-family:"微软雅黑";
    font-size:14px;
    text-align:center;
    font-weight:bold;
    float:left;
    cursor:pointer;
 }
 .dxj-ui-bd#tab.title.more-mod{
    overflow:hidden;
    border:1pxsolid#DC143C;
    width:70px;
    position:absolute;
    right:0;
    margin-right:6px;
    display:none;
 }
 .dxj-ui-bd#tab.title.more-mod.tag{
    height:32px;
    line-height:32px;
    width:70px;
    background:#DC143C;
    color:#fff;
    font-family:arial;
    font-size:12px;
    text-align:center;
    cursor:pointer;
 }
 .dxj-ui-bd#tab.title.more-mod.mods{
    overflow:hidden;
    width:70px;
    display:none;
 }
 .dxj-ui-bd#tab.title.more-mod.modsdiv{
    height:24px;
    line-height:24px;
    width:62px;
    font-family:arial;
    font-size:12px;
    cursor:pointer;
    padding-left:10px;
 }
 .dxj-ui-bd#tab.title.items{
    height:32px;
 
    width:480px;
    overflow:hidden;
    float:left;
 }
 .dxj-ui-bd#tab.title.itemsdiv{
    padding:0px;
    margin-left:10px;
    width:84px;
    height:32px;
    line-height:32px;
    background:#3385ff;
    color:#fff;
    font-family:arial;
    font-size:12px;
    text-align:center;
    position:relative;
    float:left;
    cursor:pointer;
 }
 .dxj-ui-bd#tab.title.itemsdivspan.del{
    width:16px;
    height:16px;
    line-height:16px;
    display:block;
    background:#DC143C;
    position:absolute;
    right:0;
    top:0;
    cursor:pointer;
 }
 .dxj-ui-bd#tab.content{
    width:716px;
    padding-top:30px;
    overflow:hidden;
    border:2pxsolid#3385ff;
    border-top:0px;
    min-height:130px;
    text-align:center;
 }
 .dxj-ui-bd#tab.contenttable{
    margin:0auto;
 }
 .dxj-ui-bd#tab.contentdiv.c{
    padding-top:20px;
    padding-left:20px;
    background:#eee;
    height:140px;
 }
 .dxj-ui-bd#tab.contentdiv.c.input-content{
    margin-top:10px;
    font-family:arial;
    font-size:12px;
 }
 .dxj-ui-bd#tab.console-panel{
    width:716px;
    padding-top:20px;
    padding-bottom:20px;
    overflow:hidden;
    border:2pxsolid#3385ff;
    border-top:0px;
    border-bottom:2pxsolid#3385ff;
    background:#fff;
    display:none;
 }
 
 .active{
    font-weight:bold;
 }

3,bigbear.js

复制代码代码如下:
(function($){
   varwin=window;
   varbb=win.bigbear=win.bigbear||{
       ui:{}
   };
   varui=bb.ui={};
   varTab=function(elem,opts){
       this.elem=elem;
       this.opts=opts;
   };
   vartabProto=Tab.prototype;
   /*updatetime20151/2615:36*/
   tabProto._isDisplayMax=function(size){
       vardisplayMax=this.getOpts()["displayMax"]||5;
       return(size<=displayMax)?true:false;
   };
   tabProto._isEmptyResult=function(){
       if(!this.getOpts()["result"].length){
           returnfalse;
       }
       returntrue;
   };
   tabProto._saveOrUpdateStatus=function(item,status){
       item["status"]=status;
   };
   tabProto._getItemListByStatus=function(status){
       varlist=[];
       varresult=this.getOpts()["result"];
       $.each(result,function(i,item){
           if(status==item["status"]){
               list.push(item);
           }
       });
       returnlist;
   };
   tabProto._getStatusByIndex=function(index){
       varstatus=null;
       varresult=this.getOpts()["result"];
       $.each(result,function(i,item){
           if(index==item["index"]){
               status=item["status"];
           }
       });
       returnstatus;
   };
   tabProto._renderConsolePanel=function(status){
       varthat=this;
       varroot=that.getElem().find(".console-panel");
       this._resetConsolePanel();
       $.each(that._getItemListByStatus(status),function(i,item){
           varelem=$("<divstyle="float:left";></div>").appendTo(root);
           $("<inputtype="radio"name="addmod"/>")
           .data("item",item)
           .appendTo(elem);
           $("<span></span>").text(item["text"]).appendTo(elem);
       });
       if(root.find("div").size()){
           $("<inputtype="button"value="添加模块"style="margin-left:20px"/>")
           .on("click",function(){
               vardata=root.find("input[type=radio]:checked").data("item");
               if(that._getItemListByStatus("1").length<that.getOpts()["displayMax"]){
                   that.getElem().find(".title.itemsdiv").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("暂无任何可添加的项目!");
       }
   };
   /*updatetime20151/2615:36*/ 
   tabProto._setCurrent=function(index){
       varitems=this.getElem().find(".title.itemsdiv").removeClass("active");
       items.eq(index).addClass("active");
       varcontents=this.getElem().find(".content.c").hide();
       contents.eq(index).show();
   };
   tabProto.getElem=function(){
       returnthis.elem;
   };
   tabProto.getOpts=function(){
       returnthis.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){
       varthat=this;
       this.getElem().find(".title.itemsdiv")
       .eq(elem.index())
       .fadeOut(function(){
           that._resetContent();
           that._saveOrUpdateStatus(elem.data("item"),"0");
           that._triggerItem(elem.index()+1);
       });
   };
   tabProto._triggerItem=function(next){
       varnextStatus=this._getStatusByIndex(next);
       varitems=this.getElem().find(".title.itemsdiv");
       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("暂无任何模块!");
       }
       varthat=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(){
                   varroot=$(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.itemsdiv").eq(data["index"]).fadeIn(function(){
                                   that._saveOrUpdateStatus(data,"1");
                               });
                           }
                           else{
                               alert("不能添加任何模块,目前已经是最大数量!");
                           }
                       })
                       .appendTo(root);
                   });
                   root.toggle();
               });
                
           });
       }
       this.getElem().find(".title.itemsdiv")
       .eq(0)
       .trigger("click");//假定是必须有一项,否则插件意义就不大了!
   };
   tabProto._render=function(data){
       varthat=this;
       varitem=$("<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(){
               thrownewError("NetError!");
           });
       })
       .data("item",data);
       if("2"==data["status"]){
           item.hide();
       }
       if("1"==data["showClose"]){
           $("<spanclass="del">X</span>")
           .on("click",function(){
               if(win.confirm("是否删除此项?")){
                   that._deleteItem(item);
                   returnfalse;//阻止冒泡
               }
           })
           .appendTo(item);
       }
   };
   ui.createTab=function(elem,opts){
       vartab=newTab(elem,opts);
       tab.init();
       returntab;
   };   
})(jQuery);
  

(四),最后总结

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

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

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