JavaScript插件化开发教程(六)


Posted in Javascript onFebruary 01, 2015

一,开篇分析

今天这篇文章我们说点什么那?嘿嘿嘿。我们接着上篇文章对不足的地方进行重构,以深入浅出的方式来逐步分析,让大家有一个循序渐进提高的过程。废话少说,进入正题。让我们先来回顾一下之前的

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")) ;

 } ;

效果如下图所示:

JavaScript插件化开发教程(六)

a)------非可操作状态

JavaScript插件化开发教程(六)

b)------可操作状态

JavaScript插件化开发教程(六)

(二),打开思路,进行重构

大家从代码不难看出,已经通过“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 相关文章推荐
JavaScript Sort 表格排序
Oct 31 Javascript
jquery插件开发注意事项小结
Jun 04 Javascript
AngularJS数据源的多种获取方式汇总
Feb 02 Javascript
浅谈JS中的bind方法与函数柯里化
Aug 10 Javascript
JS中with的替代方法与String中的正则方法详解
Dec 23 Javascript
详解angular element()方法使用
Apr 08 Javascript
jQuery获取table表中的td标签(实例讲解)
Jul 28 jQuery
jQuery使用zTree插件实现可拖拽的树示例
Sep 23 jQuery
在vue2.0中引用element-ui组件库的方法
Jun 21 Javascript
支付宝小程序tabbar底部导航
Nov 06 Javascript
利用JavaScript为句子加标题的3种方法示例
Jan 05 Javascript
JS前端可扩展的低代码UI框架Sunmao使用详解
Jul 23 Javascript
JavaScript插件化开发教程(五)
Feb 01 #Javascript
对JavaScript中this指针的新理解分享
Jan 31 #Javascript
IE下支持文本框和密码框placeholder效果的JQuery插件分享
Jan 31 #Javascript
有效提高JavaScript执行效率的几点知识
Jan 31 #Javascript
JavaScript日期时间与时间戳的转换函数分享
Jan 31 #Javascript
JavaScript监听和禁用浏览器回车事件实例
Jan 31 #Javascript
JavaScript编程中容易出BUG的几点小知识
Jan 31 #Javascript
You might like
受疫情影响 动画《Re从零开始的异世界生活》第二季延期至7月
2020/03/10 日漫
Discuz!5的PHP代码高亮显示插件(黑暗中的舞者更新)
2007/01/29 PHP
thinkphp判断访客为手机端或PC端的方法
2014/11/24 PHP
CodeIgniter使用smtp服务发送html邮件的方法
2015/06/10 PHP
php生出随机字符串
2017/07/06 PHP
php校验公钥是否可用的实例方法
2019/09/17 PHP
用javascript getComputedStyle获取和设置style的原理
2008/10/10 Javascript
JS函数实现动态添加CSS样式表文件
2012/12/15 Javascript
js动态给table添加/删除tr的方法
2013/08/02 Javascript
js 为label标签和div标签赋值的方法
2013/08/08 Javascript
你未必知道的JavaScript和CSS交互的5种方法
2014/04/02 Javascript
深入理解JavaScript系列(34):设计模式之命令模式详解
2015/03/03 Javascript
javascript简单实现滑动菜单效果的方法
2015/07/27 Javascript
FullCalendar日历插件应用之数据展现(一)
2015/12/23 Javascript
AngularJs ng-repeat 嵌套如何获取外层$index
2016/09/21 Javascript
Canvas 绘制粒子动画背景
2017/02/15 Javascript
AngularJS改变元素显示状态
2017/04/20 Javascript
彻底揭秘keep-alive原理(小结)
2019/05/05 Javascript
通过javascript实现段落的收缩与展开
2019/06/26 Javascript
如何对react hooks进行单元测试的方法
2019/08/14 Javascript
详解JS函数防抖
2020/06/05 Javascript
python计数排序和基数排序算法实例
2014/04/25 Python
Python  pip安装lxml出错的问题解决办法
2017/02/10 Python
pandas.DataFrame 根据条件新建列并赋值的方法
2018/04/08 Python
使用 Visual Studio Code(VSCode)搭建简单的Python+Django开发环境的方法步骤
2018/12/17 Python
pytorch: Parameter 的数据结构实例
2019/12/31 Python
在pytorch 中计算精度、回归率、F1 score等指标的实例
2020/01/18 Python
Python virtualenv虚拟环境实现过程解析
2020/04/18 Python
OpenCV+python实现实时目标检测功能
2020/06/24 Python
倩碧香港官方网站:Clinique香港
2017/11/13 全球购物
what is the difference between ext2 and ext3
2013/11/03 面试题
Python如何定义一个函数
2015/09/01 面试题
应用艺术毕业生的自我评价
2013/12/04 职场文书
单身联谊活动方案
2014/01/29 职场文书
银行开业庆典方案
2014/02/06 职场文书
行政撤诉申请书
2015/05/18 职场文书