JavaScript插件化開發(fā)教程(六)
一,開篇分析
今天這篇文章我們說點(diǎn)什么那?嘿嘿嘿。我們接著上篇文章對(duì)不足的地方進(jìn)行重構(gòu),以深入淺出的方式來(lái)逐步分析,讓大家有一個(gè)循序漸進(jìn)提高的過程。廢話少說,進(jìn)入正題。讓我們先來(lái)回顧一下之前的
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 ; // 數(shù)據(jù)游標(biāo)
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")) ;
} ;
效果如下圖所示:
a)------非可操作狀態(tài)
b)------可操作狀態(tài)
(二),打開思路,進(jìn)行重構(gòu)
大家從代碼不難看出,已經(jīng)通過“Js”中的語(yǔ)法特性,以面向?qū)ο蟮姆绞竭M(jìn)行了有效的組織,比松散的過程化形式的組織方式好多了,但是仍然會(huì)發(fā)現(xiàn)有很多不足的地方。
(1),里面重復(fù)代碼太多
?。?),職責(zé)劃分不清晰
?。?),流程梳理不健全
我們基于以上幾點(diǎn)進(jìn)行有效的重構(gòu),我們首先要梳理一下這個(gè)組件的需求,功能點(diǎn)如下:
?。?),初始化配置組件
$(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() ;
}) ;
這塊代碼很清晰,不需要做任何修改,但是大家可以基于以上配置擴(kuò)展功能,比如增加配置項(xiàng)“mode”支持多種選項(xiàng)方式。如:“checkbox勾選模式”。
接下來(lái)是要完成初始化邏輯,如下:
ISProto.init = function(){
var that = this ;
this.getOpts()["current"] = null ; // 數(shù)據(jù)游標(biāo)
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) ;
}) ;
} ;
這段代碼問題很多,職責(zé)不明確,初始化邏輯包含了功能點(diǎn)的細(xì)節(jié)實(shí)現(xiàn)。
再繼續(xù)看渲染部分代碼:
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")) ;
} ;
問題很明顯,發(fā)現(xiàn)了重復(fù)性的操作,應(yīng)該進(jìn)行合理的抽象,已達(dá)到復(fù)用的目的。
整個(gè)組建的流程包括初始化,渲染(事件綁定),還有就是相關(guān)的數(shù)據(jù)操作方法以及dom操作的輔助方法。
綜上所述,經(jīng)過簡(jiǎn)單的梳理后,我們應(yīng)該建立起功能的操作目的以及流程主線的任務(wù)分配,各負(fù)其責(zé)。
所以我們重構(gòu)的目的很明確了,對(duì)!就是進(jìn)行功能點(diǎn)的抽象,友好的職責(zé)劃分,那么我們?nèi)绾螌?shí)現(xiàn)那?
第一步,建立流程功能方法:(方法接口)
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 !
} ;
第三步,建立數(shù)據(jù)操作接口:
ISProto._setCurrent = function(){
// put you code here !
} ;
ISProto._getCurrent = function(){
// put you code here !
} ;
還有一些參照下面的完整源碼,這里只是說的思路。
(三),完整代碼以供學(xué)習(xí),本代碼已經(jīng)過測(cè)試
function ItemSelector(elem,opts){
this.elem = elem ;
this.opts = opts ;
this.current = -1 ; // 數(shù)據(jù)游標(biāo)
} ;
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")) ;
} ;
(四),最后總結(jié)
?。?),面向?qū)ο蟮乃伎挤绞胶侠矸治龉δ苄枨蟆?/p>
?。?),以類的方式來(lái)組織我們的插件邏輯。
?。?),不斷重構(gòu)上面的實(shí)例,如何進(jìn)行合理的重構(gòu)那?不要設(shè)計(jì)過度,要游刃有余,推薦的方式是過程化設(shè)計(jì)與面向?qū)ο笏枷朐O(shè)計(jì)相結(jié)合。
(4),下篇文章中會(huì)擴(kuò)展相關(guān)功能,比如“mode”這個(gè)屬性,為"1"時(shí)支持checkbox多選模式,現(xiàn)在只是默認(rèn)下拉模式。
看我本文,是不是要比上一篇代碼優(yōu)秀了很多呢,小伙伴們自己做項(xiàng)目也應(yīng)該多想多做,盡量使自己的代碼更加的合理。
- JavaScript插件化開發(fā)教程(五)
- JavaScript插件化開發(fā)教程 (四)
- JavaScript插件化開發(fā)教程 (三)
- JavaScript插件化開發(fā)教程 (二)
- JavaScript插件化開發(fā)教程 (一)
- 一看就懂的Android APP開發(fā)入門教程
- Android中利用App實(shí)現(xiàn)消息推送機(jī)制的代碼
- Android筆記之:App應(yīng)用之啟動(dòng)界面SplashActivity的使用
- Android 避免APP啟動(dòng)閃黑屏的解決辦法(Theme和Style)
- 親自動(dòng)手實(shí)現(xiàn)Android App插件化
相關(guān)文章
67 個(gè)節(jié)約開發(fā)時(shí)間的前端開發(fā)者的工具、庫(kù)和資源
在本文中,我不會(huì)去談 React、Angular、Vue 等等這些大的前端框架,也不會(huì)談 Atom、VS code、Sublime 等等這些已經(jīng)很出名的代碼編輯器,我只是想簡(jiǎn)單的分享一套我認(rèn)為有助于提升開發(fā)者工作流的工具集2017-09-09微信小程序?qū)崿F(xiàn)點(diǎn)擊生成隨機(jī)驗(yàn)證碼
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)點(diǎn)擊生成隨機(jī)驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09淺談JavaScript中運(yùn)算符的優(yōu)先級(jí)
這篇文章主要給大家簡(jiǎn)單介紹了JavaScript中運(yùn)算符的優(yōu)先級(jí)的相關(guān)問題,十分的實(shí)用,有需要的小伙伴可以參考下。2015-07-07javascript 在firebug調(diào)試時(shí)用console.log的方法
當(dāng)你使用console.log()函數(shù)時(shí),下面的firebug一定要打開,不然這函數(shù)在用firefox運(yùn)行時(shí)無(wú)效且影響正常程序,如果用IE打開,將會(huì)出錯(cuò)2012-05-05詳解JavaScript的內(nèi)存空間、賦值和深淺拷貝
這篇文章主要介紹了JavaScript的內(nèi)存空間、賦值和深淺拷貝,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04JS SetInterval 代碼實(shí)現(xiàn)頁(yè)面輪詢
setInterval 是一個(gè)實(shí)現(xiàn)定時(shí)調(diào)用的函數(shù),可按照指定的周期(以毫秒計(jì))來(lái)調(diào)用函數(shù)或計(jì)算表達(dá)式。下面通過本文給大家分享JS SetInterval 代碼實(shí)現(xiàn)頁(yè)面輪詢,感興趣的朋友一起看看吧2017-08-08javascript自動(dòng)生成包含數(shù)字與字符的隨機(jī)字符串
這篇文章主要介紹了javascript自動(dòng)生成包含數(shù)字與字符的隨機(jī)字符串,涉及Math.random()和Math.floor()兩個(gè)函數(shù)的使用技巧,需要的朋友可以參考下2015-02-02js仿蘋果iwatch外觀的計(jì)時(shí)器代碼分享
這篇文章主要介紹了JS+CSS3實(shí)現(xiàn)的類似于蘋果iwatch計(jì)時(shí)器特效,很實(shí)用的代碼,推薦給大家,有需要的小伙伴可以參考下。2015-08-08