一,开篇分析
今天这篇文章我们说点什么那?嘿嘿嘿。我们接着上篇文章对不足的地方进行重构,以深入浅出的方式来逐步分析,让大家有一个循序渐进提高的过程。废话少说,进入正题。让我们先来回顾一下之前的
js部分的代码,如下:
复制代码 代码如下:
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 = $(
)
.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)) ;
} ;
效果如下图所示:
a)------非可操作状态
b)------可操作状态
(二),打开思路,进行重构
大家从代码不难看出,已经通过“js”中的语法特性,以面向对象的方式进行了有效的组织,比松散的过程化形式的组织方式好多了,但是仍然会发现有很多不足的地方。
(1),里面重复代码太多
(2),职责划分不清晰
(3),流程梳理不健全
我们基于以上几点进行有效的重构,我们首先要梳理一下这个组件的需求,功能点如下:
(1),初始化配置组件
复制代码 代码如下:
$(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勾选模式”。
接下来是要完成初始化逻辑,如下:
复制代码 代码如下:
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._render = function(item){
var that = this ;
var itemelem = $(
)
.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操作的辅助方法。
综上所述,经过简单的梳理后,我们应该建立起功能的操作目的以及流程主线的任务分配,各负其责。
所以我们重构的目的很明确了,对!就是进行功能点的抽象,友好的职责划分,那么我们如何实现那?
第一步,建立流程功能方法:(方法接口)
复制代码 代码如下:
isproto.init = function(){
// put you code here !
} ;
isproto._render = function(){
// put you code here !
} ;
第二部,建立抽象后的方法接口:
复制代码 代码如下:
isproto._fnitemselectordelegatehandler = function(){
// put you code here !
} ;
isproto._fntriggerhandler = function(){
// put you code here !
} ;
isproto._addorremoveclass = function(){
// put you code here !
} ;
第三步,建立数据操作接口:
复制代码 代码如下:
isproto._setcurrent = function(){
// put you code here !
} ;
isproto._getcurrent = function(){
// put you code here !
} ;
还有一些参照下面的完整源码,这里只是说的思路。(三),完整代码以供学习,本代码已经过测试
复制代码 代码如下:
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 = $(
).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)) ;
} ;
(四),最后总结
(1),面向对象的思考方式合理分析功能需求。
(2),以类的方式来组织我们的插件逻辑。
(3),不断重构上面的实例,如何进行合理的重构那?不要设计过度,要游刃有余,推荐的方式是过程化设计与面向对象思想设计相结合。
(4),下篇文章中会扩展相关功能,比如“mode”这个属性,为1时支持checkbox多选模式,现在只是默认下拉模式。
看我本文,是不是要比上一篇代码优秀了很多呢,小伙伴们自己做项目也应该多想多做,尽量使自己的代码更加的合理。
