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生成/解析dom的CDATA类型的字段的代码
Apr 22 Javascript
JS获取计算机mac地址以及IP的实现方法
Jan 08 Javascript
EsLint入门学习教程
Feb 17 Javascript
jQuery实现的背景颜色渐变动画效果示例
Mar 24 jQuery
vue父组件向子组件动态传值的两种方法
Nov 11 Javascript
在vue里面设置全局变量或数据的方法
Mar 09 Javascript
微信小程序调用摄像头隐藏式拍照功能
Aug 22 Javascript
JS使用栈判断给定字符串是否是回文算法示例
Mar 04 Javascript
Vue keepAlive 数据缓存工具实现返回上一个页面浏览的位置
May 10 Javascript
Node.js爬虫如何获取天气和每日问候详解
Aug 26 Javascript
BootstrapValidator验证用户名已存在(ajax)
Nov 08 Javascript
Vue实现手机扫描二维码预览页面效果
May 28 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
PHP在Web开发领域的优势
2006/10/09 PHP
PHP图片上传类带图片显示
2006/11/25 PHP
php将会员数据导入到ucenter的代码
2010/07/18 PHP
学习php设计模式 php实现命令模式(command)
2015/12/08 PHP
js 完美图片新闻轮转效果,腾讯大粤网首页图片轮转改造而来
2011/11/21 Javascript
关于js遍历表格的实例
2013/07/10 Javascript
jquery封装的对话框简单实现
2013/07/21 Javascript
用javascript添加控件自定义属性解析
2013/11/25 Javascript
JavaScript打印网页指定区域的例子
2014/05/03 Javascript
javascript图片预加载实例分析
2015/07/16 Javascript
JS+CSS实现滑动切换tab菜单效果
2015/08/25 Javascript
JavaScript创建防篡改对象的方法分析
2018/12/30 Javascript
[02:38]2018DOTA2亚洲邀请赛赛前采访-VGJ.T
2018/04/03 DOTA
[52:12]FNATIC vs Infamous 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/19 DOTA
[37:45]完美世界DOTA2联赛PWL S3 LBZS vs Phoenix 第二场 12.09
2020/12/11 DOTA
Python实现Tab自动补全和历史命令管理的方法
2015/03/12 Python
Django框架使用富文本编辑器Uedit的方法分析
2018/07/31 Python
Win10下python 2.7.13 安装配置方法图文教程
2018/09/18 Python
Python3标准库总结
2019/02/19 Python
Golang GBK转UTF-8的例子
2019/08/26 Python
python print 格式化输出,动态指定长度的实现
2020/04/12 Python
python如何将图片转换素描画
2020/09/08 Python
viagogo波兰票务平台:演唱会、体育比赛、戏剧门票
2018/04/23 全球购物
车库门开启器、遥控器和零件:Chamberlain
2019/04/09 全球购物
给孩子的新年寄语
2014/04/08 职场文书
国旗下的演讲稿
2014/05/08 职场文书
小学校园之星事迹材料
2014/05/16 职场文书
年终奖发放方案
2014/06/02 职场文书
纪律教育月活动总结
2014/08/26 职场文书
贫困证明模板(3篇)
2014/09/16 职场文书
工商局个人工作总结
2015/03/03 职场文书
2015新教师教学工作总结
2015/07/22 职场文书
医院中层管理人员培训心得体会
2016/01/11 职场文书
2019年思想汇报
2019/06/20 职场文书
奶茶店的创业计划书该怎么写?
2019/07/15 职场文书
小学四年级作文之人物作文
2019/11/06 职场文书