JavaScript插件化开发方式
一,开篇分析
今天这篇文章我们说点什么那?嘿嘿嘿。我们接着上篇文章对不足的地方进行重构,以深入浅出的方式来逐步分析,让大家有一个循序渐进提高的过程。废话少说,进入正题。让我们先来回顾一下之前的
Js部分的代码,如下:
复制代码 代码如下:
function ItemSelector(elem,opts){
= elem ;
= opts ;
} ;
var ISProto = otype ;
lem = function(){
return ;
} ;
pts = function(){
return ;
} ;
/* data manip*/
ISProto._setCurrent = function(current){
pts()["current"] = current ;
} ;
urrentValue = function(current){
return pts()["current"] ;
} ;
/* data manip*/
= function(){
var that = this ;
pts()["current"] = null ; // 数据游标
this._setItemValue(pts()["currentText"]) ;
var itemsElem = lem()("ent s") ;
lem()("e div")("click",function(){
le() ;
}) ;
lem()("e span")("click",function(){
le() ;
}) ;
$(pts()["items"],function(i,item){
item["id"] = (new Date()ime())ring() ;
that._render(item) ;
}) ;
} ;
ISProto._setItemValue = function(value){
lem()("e div")(value)
} ;
ISProto._render = function(item){
var that = this ;
var itemElem = $("
")
(item["text"])
("id",item["id"]) ;
if("0" == item["disabled"]){
("click",function(){
var onChange = pts()["change"] ;
lem()("ent s")() ;
that._setItemValue(item["text"]) ;
that._setCurrent(item) ;
onChange && onChange(item) ;
})
eover(function(){
$(this)lass("item-hover") ;
})
eout(function(){
$(this)veClass("item-hover") ;
}) ;
}
else{
("color","#ccc")("click",function(){
lem()("ent s")() ;
that._setItemValue(item["text"]) ;
}) ;
}
ndTo(lem()("ent s")) ;
} ;
效果如下图所示:
a)------非可操作状态
b)------可操作状态
(二),打开思路,进行重构
大家从代码不难看出,已经通过“Js”中的语法特性,以面向对象的方式进行了有效的组织,比松散的过程化形式的组织方式好多了,但是仍然会发现有很多不足的地方。
(1),里面重复代码太多
(2),职责划分不清晰
我们基于以上几点进行有效的重构,我们首先要梳理一下这个组件的需求,功能点如下:
(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"
}
] ,
}) ;
() ;
}) ;
这块代码很清晰,不需要做任何修改,但是大家可以基于以上配置扩展功能,比如增加配置项“mode”支持多种选项方式。如:“checkbox勾选模式”。
接下来是要完成初始化逻辑,如下:
复制代码 代码如下:
= function(){
var that = this ;
pts()["current"] = null ; // 数据游标
this._setItemValue(pts()["currentText"]) ;
var itemsElem = lem()("ent s") ;
lem()("e div")("click",function(){
le() ;
}) ;
lem()("e span")("click",function(){
le() ;
}) ;
$(pts()["items"],function(i,item){
item["id"] = (new Date()ime())ring() ;
that._render(item) ;
}) ;
} ;
这段代码问题很多,职责不明确,初始化逻辑包含了功能点的细节实现。
再继续看渲染部分代码:
复制代码 代码如下:
ISProto._render = function(item){
var that = this ;
var itemElem = $("
")
(item["text"])
("id",item["id"]) ;
if("0" == item["disabled"]){
("click",function(){
var onChange = pts()["change"] ;
lem()("ent s")() ;
that._setItemValue(item["text"]) ;
that._setCurrent(item) ;
onChange && onChange(item) ;
})
eover(function(){
$(this)lass("item-hover") ;
})
eout(function(){
$(this)veClass("item-hover") ;
}) ;
}
else{
("color","#ccc")("click",function(){
lem()("ent s")() ;
that._setItemValue(item["text"]) ;
}) ;
}
ndTo(lem()("ent s")) ;
} ;
问题很明显,发现了重复性的操作,应该进行合理的'抽象,已达到复用的目的。
整个组建的流程包括初始化,渲染(事件绑定),还有就是相关的数据操作方法以及dom操作的辅助方法。
综上所述,经过简单的梳理后,我们应该建立起功能的操作目的以及流程主线的任务分配,各负其责。
所以我们重构的目的很明确了,对!就是进行功能点的抽象,友好的职责划分,那么我们如何实现那?
第一步,建立流程功能方法:(方法接口)
复制代码 代码如下:
= 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){
= elem ;
= opts ;
ent = -1 ; // 数据游标
} ;
var ISProto = otype ;
/* getter api*/
lem = function(){
return ;
} ;
pts = function(){
return ;
} ;
ISProto._getCurrent = function(){
return ent ;
} ;
/* getter api*/
/* data manip*/
ISProto._setCurrent = function(current){
ent = current ;
} ;
ISProto._setItemText = function(text){
lem()("e div")(text) ;
} ;
/* data manip*/
/* on 2015 1/31 23:38 */
ISProto._fnTriggerHandler = function(index,text,value){
if(this._isDisabled(value)){
index = -1 ;
text = pts()["currentText"] ;
}
this._setItemText(text) ;
this._setCurrent(index) ;
lem()("ent s")() ;
} ;
ISProto._addOrRemoveClass = function(elem,className,addIs){
if(addIs){
lass(className) ;
}
else{
veClass(className) ;
}
} ;
ISProto._fnItemSelectorDelegateHandler = function(){
var that = this ;
lem()("click","[data-toggle]",function(){
lem()("ent s")le() ;
}) ;
} ;
ISProto._isDisabled = function(value){
return ("1" == value) ? true : false ;
} ;
/* on 2015 1/31 23:38 */
= function(){
var that = this ;
this._fnItemSelectorDelegateHandler() ;
$(pts()["items"],function(i,item){
item["index"] = i ;
that._render(item) ;
}) ;
this._fnTriggerHandler(this._getCurrent(),pts()["currentText"],"1") ;
} ;
ISProto._render = function(item){
var that = this ;
var itemElem = $("
")(item["text"])("id",item["index"]) ;
var activeClass = ("0" == item["disabled"]) " : "item-disabled-hover" ;
("click",function(){
that._fnTriggerHandler(item["index"],item["text"],item["disabled"]) ;
})
eover(function(){
that._addOrRemoveClass($(this),activeClass,true) ;
})
eout(function(){
that._addOrRemoveClass($(this),activeClass,false) ;
}) ;
ndTo(lem()("ent s")) ;
} ;
(四),最后总结
(1),面向对象的思考方式合理分析功能需求。
(2),以类的方式来组织我们的插件逻辑。
(3),不断重构上面的实例,如何进行合理的重构那?不要设计过度,要游刃有余,推荐的方式是过程化设计与面向对象思想设计相结合。
(4),下篇文章中会扩展相关功能,比如“mode”这个属性,为"1"时支持checkbox多选模式,现在只是默认下拉模式。
看我本文,是不是要比上一篇代码优秀了很多呢,小伙伴们自己做项目也应该多想多做,尽量使自己的代码更加的合理。
-
如何理解Javascript的caller,callee,call,apply区别
在提到上述的概念之前,首先想说说javascript中函数的隐含参数:argumentsarguments该对象代表正在执行的函数和调用它的函数的参数。[function.]arguments[n]参数function:选项。当前正在执行的Function对象的名字。n:选项。要传递给Function对象的从0开始的参数值...
-
如何理解Javascript的caller,callee,call,apply区别
在提到上述的概念之前,首先想说说javascript中函数的隐含参数:argumentsarguments该对象代表正在执行的函数和调用它的函数的参数。[function.]arguments[n]参数function:选项。当前正在执行的Function对象的名字。n:选项。要传递给Function对象的从0开始的参数值...
-
SQl常用增删改查模板
篇一:SQl常用增删改查SQL常用增删改查语句增加现在有一张表,表(Test)里面有三个字段,分别为sno,sname,age。举例用一条增加SQL语句,插入一条数据进库。语句:Insertinto表名value(‘数据1’,’数据2’,’数据3’)具体操作:Insertintotestvalues('test','te...
-
asp.net 操作INI文件读写类实例代码
操作INI文件读写类实例代码复制代码代码如下:usingSystem;usingropServices;using;using;namespaceCommon{//////INI文件读写类。///publicclassINIFile{publicstringpath;publicINIFile(stringINIPath){path=INIPath;}[DllImport("kernel32")]privatestaticex...