源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

JavaScript插件化开发教程(六)

  • 时间:2022-04-15 01:00 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:JavaScript插件化开发教程(六)
[b]一,开篇分析[/b] 今天这篇文章我们说点什么那?嘿嘿嘿。我们接着上篇文章对不足的地方进行重构,以深入浅出的方式来逐步分析,让大家有一个循序渐进提高的过程。废话少说,进入正题。让我们先来回顾一下之前的 Js部分的代码,如下:
[u]复制代码[/u] 代码如下:
 function ItemSelector(elem,opts){      this.elem = elem ;      this.opts = opts ;  } ;  var ISProto = ItemSelector.prototype ;  ISProto.getElem = function(){      return this.elem ;  } ;  ISProto.getOpts = function(){      return this.opts ;  } ;  /* data manip*/  ISProto._setCurrent = function(current){      this.getOpts()["current"] = current ;  } ;  ISProto.getCurrentValue = function(current){      return this.getOpts()["current"] ;  } ;  /* data manip*/  ISProto.init = function(){      var that = this ;      this.getOpts()["current"] = null ; // 数据游标      this._setItemValue(this.getOpts()["currentText"]) ;      var itemsElem = that.getElem().find(".content .items") ;      this.getElem().find(".title div").on("click",function(){          itemsElem.toggle() ;      }) ;      this.getElem().find(".title span").on("click",function(){          itemsElem.toggle() ;      }) ;      $.each(this.getOpts()["items"],function(i,item){          item["id"] = (new Date().getTime()).toString() ;          that._render(item) ;      }) ;  } ;  ISProto._setItemValue = function(value){      this.getElem().find(".title div").text(value)  } ;  ISProto._render = function(item){      var that = this ;      var itemElem = $("<div></div>")      .text(item["text"])      .attr("id",item["id"]) ;      if("0" == item["disabled"]){          itemElem.on("click",function(){              var onChange = that.getOpts()["change"] ;              that.getElem().find(".content .items").hide() ;              that._setItemValue(item["text"]) ;              that._setCurrent(item) ;              onChange && onChange(item) ;          })          .mouseover(function(){              $(this).addClass("item-hover") ;          })          .mouseout(function(){              $(this).removeClass("item-hover") ;          }) ;      }      else{          itemElem.css("color","#ccc").on("click",function(){              that.getElem().find(".content .items").hide() ;              that._setItemValue(item["text"]) ;          }) ;      }      itemElem.appendTo(this.getElem().find(".content .items")) ;  } ;
  效果如下图所示: [img]http://files.jb51.net/file_images/article/201502/201502010935444.png[/img]   a)------非可操作状态 [img]http://files.jb51.net/file_images/article/201502/201502010935445.png[/img]   b)------可操作状态 [img]http://files.jb51.net/file_images/article/201502/201502010935456.png[/img] [b](二),打开思路,进行重构[/b]   大家从代码不难看出,已经通过“Js”中的语法特性,以面向对象的方式进行了有效的组织,比松散的过程化形式的组织方式好多了,但是仍然会发现有很多不足的地方。   (1),里面重复代码太多   (2),职责划分不清晰   (3),流程梳理不健全   我们基于以上几点进行有效的重构,我们首先要梳理一下这个组件的需求,功能点如下:   (1),初始化配置组件
[u]复制代码[/u] 代码如下:
 $(function(){      var itemSelector = new ItemSelector($("#item-selector"),{          currentText : "Please Choose Item" ,          items : [              {                  text : "JavaScript" ,                  value : "js" ,                  disabled : "1"              } ,              {                  text : "Css" ,                  value : "css" ,                  disabled : "0"              } ,              {                  text : "Html" ,                  value : "html" ,                  disabled : "0"              }          ] ,      }) ;      itemSelector.init() ;  }) ;
  这块代码很清晰,不需要做任何修改,但是大家可以基于以上配置扩展功能,比如增加配置项“mode”支持多种选项方式。如:“checkbox勾选模式”。   接下来是要完成初始化逻辑,如下:
[u]复制代码[/u] 代码如下:
 ISProto.init = function(){      var that = this ;      this.getOpts()["current"] = null ; // 数据游标      this._setItemValue(this.getOpts()["currentText"]) ;      var itemsElem = that.getElem().find(".content .items") ;      this.getElem().find(".title div").on("click",function(){          itemsElem.toggle() ;      }) ;      this.getElem().find(".title span").on("click",function(){          itemsElem.toggle() ;      }) ;      $.each(this.getOpts()["items"],function(i,item){          item["id"] = (new Date().getTime()).toString() ;          that._render(item) ;      }) ;  } ;
  这段代码问题很多,职责不明确,初始化逻辑包含了功能点的细节实现。   再继续看渲染部分代码:
[u]复制代码[/u] 代码如下:
 ISProto._render = function(item){      var that = this ;      var itemElem = $("<div></div>")      .text(item["text"])      .attr("id",item["id"]) ;      if("0" == item["disabled"]){          itemElem.on("click",function(){              var onChange = that.getOpts()["change"] ;              that.getElem().find(".content .items").hide() ;              that._setItemValue(item["text"]) ;              that._setCurrent(item) ;              onChange && onChange(item) ;          })          .mouseover(function(){              $(this).addClass("item-hover") ;          })          .mouseout(function(){              $(this).removeClass("item-hover") ;          }) ;      }      else{          itemElem.css("color","#ccc").on("click",function(){              that.getElem().find(".content .items").hide() ;              that._setItemValue(item["text"]) ;          }) ;      }      itemElem.appendTo(this.getElem().find(".content .items")) ;  } ;
  问题很明显,发现了重复性的操作,应该进行合理的抽象,已达到复用的目的。   整个组建的流程包括初始化,渲染(事件绑定),还有就是相关的数据操作方法以及dom操作的辅助方法。   综上所述,经过简单的梳理后,我们应该建立起功能的操作目的以及流程主线的任务分配,各负其责。   所以我们重构的目的很明确了,对!就是进行功能点的抽象,友好的职责划分,那么我们如何实现那?   第一步,建立流程功能方法:(方法接口)
[u]复制代码[/u] 代码如下:
ISProto.init = function(){    // put you code here ! } ; ISProto._render = function(){    // put you code here ! } ;
 第二部,建立抽象后的方法接口:
[u]复制代码[/u] 代码如下:
ISProto._fnItemSelectorDelegateHandler = function(){    // put you code here ! } ; ISProto._fnTriggerHandler = function(){    // put you code here ! } ; ISProto._addOrRemoveClass = function(){    // put you code here ! } ;
第三步,建立数据操作接口:
[u]复制代码[/u] 代码如下:
 ISProto._setCurrent = function(){     // put you code here !  } ;  ISProto._getCurrent = function(){     // put you code here !  } ;
  还有一些参照下面的完整源码,这里只是说的思路。 (三),完整代码以供学习,本代码已经过测试
[u]复制代码[/u] 代码如下:
function ItemSelector(elem,opts){     this.elem = elem ;     this.opts = opts ;     this.current = -1 ; // 数据游标 } ; var ISProto = ItemSelector.prototype ; /* getter api*/ ISProto.getElem = function(){     return this.elem ; } ; ISProto.getOpts = function(){     return this.opts ; } ; ISProto._getCurrent = function(){     return this.current ; } ; /* getter api*/ /* data manip*/ ISProto._setCurrent = function(current){     this.current = current ; } ; ISProto._setItemText = function(text){     this.getElem().find(".title div").text(text) ; } ; /* data manip*/   /* update on 2015 1/31 23:38 */ ISProto._fnTriggerHandler = function(index,text,value){     if(this._isDisabled(value)){         index = -1 ;         text = this.getOpts()["currentText"] ;     }     this._setItemText(text) ;     this._setCurrent(index) ;     this.getElem().find(".content .items").hide() ; } ; ISProto._addOrRemoveClass = function(elem,className,addIs){     if(addIs){         elem.addClass(className) ;     }     else{         elem.removeClass(className) ;     } } ; ISProto._fnItemSelectorDelegateHandler = function(){     var that = this ;     this.getElem().on("click","[data-toggle]",function(){         that.getElem().find(".content .items").toggle() ;     }) ; } ; ISProto._isDisabled = function(value){     return ("1" == value) ? true : false ; } ; /* update on 2015 1/31 23:38 */ ISProto.init = function(){     var that = this ;     this._fnItemSelectorDelegateHandler() ;     $.each(this.getOpts()["items"],function(i,item){         item["index"] = i ;         that._render(item) ;     }) ;     this._fnTriggerHandler(this._getCurrent(),this.getOpts()["currentText"],"1") ; } ; ISProto._render = function(item){     var that = this ;     var itemElem = $("<div></div>").text(item["text"]).attr("id",item["index"]) ;     var activeClass = ("0" == item["disabled"]) ? "item-hover" : "item-disabled-hover" ;     itemElem.on("click",function(){         that._fnTriggerHandler(item["index"],item["text"],item["disabled"]) ;     })     .mouseover(function(){         that._addOrRemoveClass($(this),activeClass,true) ;     })     .mouseout(function(){         that._addOrRemoveClass($(this),activeClass,false) ;     }) ;     itemElem.appendTo(this.getElem().find(".content .items")) ; } ;
   [b](四),最后总结[/b]   (1),面向对象的思考方式合理分析功能需求。   (2),以类的方式来组织我们的插件逻辑。   (3),不断重构上面的实例,如何进行合理的重构那?不要设计过度,要游刃有余,推荐的方式是过程化设计与面向对象思想设计相结合。     (4),下篇文章中会扩展相关功能,比如“mode”这个属性,为"1"时支持checkbox多选模式,现在只是默认下拉模式。 看我本文,是不是要比上一篇代码优秀了很多呢,小伙伴们自己做项目也应该多想多做,尽量使自己的代码更加的合理。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部