大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ ItemSelector重构完结版)
一,开篇分析
Hi,大家好!大熊君又和大家见面了,还记得上一篇文章吗。主要讲述了以“jQuery的方式如何开发插件”,以及过程化设计与面向对象思想设计相结合的方式是
如何设计一个插件的,两种方式各有利弊取长补短,本系列文章是以学习为导向的,具体场景大家自己定夺使用方式。那么今天这篇文章我们说点什么那?嘿嘿嘿
。我们接着上篇文章对不足的地方进行重构,以深入浅出的方式来逐步分析,让大家有一个循序渐进提高的过程。废话少说,进入正题。让我们先来回顾一下之前的
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 = $("<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)------非可操作状态

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 = $("<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操作的辅助方法。
综上所述,经过简单的梳理后,我们应该建立起功能的操作目的以及流程主线的任务分配,各负其责。
所以我们重构的目的很明确了,对!就是进行功能点的抽象,友好的职责划分,那么我们如何实现那?
第一步,建立流程功能方法:(方法接口)
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 = $("<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")) ;
} ;
(四),最后总结
(1),面向对象的思考方式合理分析功能需求。
(2),以类的方式来组织我们的插件逻辑。
(3),不断重构上面的实例,如何进行合理的重构那?不要设计过度,要游刃有余,推荐的方式是过程化设计与面向对象思想设计相结合。
(4),下篇文章中会扩展相关功能,比如“mode”这个属性,为"1"时支持checkbox多选模式,现在只是默认下拉模式。
哈哈哈,本篇结束,未完待续,希望和大家多多交流够沟通,共同进步。。。。。。呼呼呼……(*^__^*)
大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ ItemSelector重构完结版)的更多相关文章
- 大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ ItemSelector)
一,开篇分析 Hi,大家好!大熊君又和大家见面了,还记得前两篇文章吗.主要讲述了以“jQuery的方式如何开发插件”,以及过程化设计与面向对象思想设计相结合的方式是 如何设计一个插件的,两种方式各有利 ...
- 大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ ProcessBar)
一,开篇分析 Hi,大家好!大熊君又和大家见面了,还记得前两篇文章吗.主要讲述了以“jQuery的方式如何开发插件”,以及过程化设计与面向对象思想设计相结合的方式是 如何设计一个插件的,两种方式各有利 ...
- 大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ Tab)
一,开篇分析 Hi,大家好!大熊君又和大家见面了,还记得前两篇文章吗.主要讲述了以“jQuery的方式如何开发插件”,以及过程化设计与面向对象思想设计相结合的方式是 如何设计一个插件的,两种方式各有利 ...
- 大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ Tab功能扩展完结版)
一,开篇分析 Hi,大家好!大熊君又和大家见面了,还记得上一篇文章吗.主要讲述了一个“Tab”插件是如何组织代码以及实现的”,以及过程化设计与面向对象思想设计相结合的方式是 如何设计一个插件的,两种方 ...
- 大熊君JavaScript插件化开发------(第二季)
一,开篇分析 Hi,大家好!大熊君又和大家见面了,还记得昨天的那篇文章吗------这个系列的开篇(第一季).主要讲述了以“jQuery的方式如何开发插件”, 那么今天我们带着昨天的疑问来继续我们的插 ...
- 大熊君JavaScript插件化开发------(第一季)
一,开篇分析 Hi,大家!大熊君又来了,今天这系列文章主要是说说如何开发基于“JavaScript”的插件式开发,我想很多人对”插件“这个词并不陌生, 有的人可能叫“组件”或“部件”,这不重要,关键是 ...
- JavaScript插件化开发
大熊君JavaScript插件化开发 一,开篇分析 Hi,大家好!大熊君又和大家见面了,还记得昨天的那篇文章吗------这个系列的开篇(第一季).主要讲述了以“jQuery的方式如何开发插件”, 那 ...
- 又一开源项目爆火于GitHub,Android高级插件化强化实战
一.插件化起源 插件化技术最初源于免安装运行 Apk的想法,这个免安装的 Apk 就可以理解为插件,而支持插件的 app 我们一般叫 宿主. 想必大家都知道,在 Android 系统中,应用是以 Ap ...
- TinyFrame升级之八:实现简易插件化开发
本章主要讲解如何为框架新增插件化开发功能. 在.net 4.0中,我们可以在Application开始之前,通过PreApplicationStartMethod方法加载所需要的任何东西.那么今天我们 ...
随机推荐
- microstrip patch antenna
微带天线有很多优点,低成本,易于集成,加工简单,缺点有:效率低.功率容易低.高Q值 ,可能存在表面波,极化效果差,弱电扫性能.带宽窄.微带线的金属厚度t远远小于波长(t << λ0 ,自由 ...
- flush和reflush
/** * jpa 中的reflush 同 hibernate 中 Session 的 refresh 方法. * * reflush 会强制发送sql查询(select)语句,使缓存中的数据和数据库 ...
- Maven配置详见
CSDN 2016博客之星评选结果公布 [系列直播]零基础学习微信小程序! "我的2016"主题征文活动 博客的神秘功能 maven 配置详解 标签: mave ...
- Mysql操作初级
Mysql操作初级 本节内容 数据库概述 数据库安装 数据库操作 数据表操作 表内容操作 1.数据库概述 数据库管理系统叫做DBMS 1.什么是数据库 ? 答:数据的仓库,如:在ATM的示例中我们创建 ...
- C#.NET 大型企业信息化系统集成快速开发平台 4.2 版本 - 所有的基础数据都可以恢复删除
客户的需求如下: 所有基礎信息需要記錄創建人,創建時間,更改人,更改時間,刪除人,刪除時間.有停用基礎信息功能(停用不是刪除,只是暫時停用).基礎信息可以查出已經刪除的信息(有選項可以選擇),有方法把 ...
- 十分钟轻松让你认识Entity Framework 7
EF7不是在EF6上更新,而是完全重写了.它完全支持.NET Core runtime,也就是说以后你可以在Mac或者是Linux机器上使用EF了. https://github.com/nichol ...
- PHP引用(&)使用详解
初学php关于&引用 官方文档: 1.引用是什么:http://www.php.net/manual/zh/language.references.whatare.php 2.引用做什么:ht ...
- 音乐播放器 EasyMusic (一)
EasyMusic 一. 代码获取 github 上链接为 https://github.com/VincentWYJ/EasyMusic, 感兴趣的朋友可以同步下来看, 欢迎提出宝贵意见或建议. 1 ...
- canvas缓动3
这次缓动的是旋转旋转,写完之后才知道原来rotate是绕原点旋转,而且还带着rect本身的X与Y一起,所以我采用了translate达到位移效果,以免旋转到画布外面去,画完之后效果惨不忍睹,原来是忘记 ...
- java 异步处理
详情请看:http://www.cnblogs.com/yezhenhan/archive/2012/01/07/2315645.html 引入ExecutorService 类 private st ...