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 相关文章推荐
不要在cookie中使用特殊字符的原因分析
Jul 13 Javascript
Javascript面象对象成员、共享成员变量实验
Nov 19 Javascript
js multiple全选与取消全选实现代码
Dec 04 Javascript
js中的getAttribute方法使用示例
Aug 01 Javascript
jquery获取所有选中的checkbox实现代码
May 26 Javascript
微信JS-SDK坐标位置如何转换为百度地图坐标
Jul 04 Javascript
AngularJs表单验证实例代码解析
Nov 29 Javascript
JavaScript编写一个贪吃蛇游戏
Mar 09 Javascript
基于vue2.0实现的级联选择器
Jun 09 Javascript
解决循环中setTimeout执行顺序的问题
Jun 20 Javascript
详解在vue-cli中使用graphql即vue-apollo的用法
Sep 08 Javascript
微信小程序自定义tabBar在uni-app的适配详解
Sep 30 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中对数据库操作的封装
2006/10/09 PHP
通过PHP修改Linux或Unix口令的方法分享
2012/01/30 PHP
PHP数字字符串左侧补0、字符串填充和自动补齐的几种方法
2014/05/10 PHP
简单分析ucenter 会员同步登录通信原理
2014/08/25 PHP
如何使用纯PHP实现定时器任务(Timer)
2015/07/31 PHP
PHP实现微信支付(jsapi支付)流程步骤详解
2018/03/15 PHP
dtree 网页树状菜单及传递对象集合到js内,动态生成节点
2012/04/14 Javascript
防止xss和sql注入:JS特殊字符过滤正则
2013/04/18 Javascript
js检测网络是否具体连接功能的代码
2014/05/23 Javascript
jQuery的缓存机制浅析
2014/06/07 Javascript
Javascript中的关键字和保留字整理
2014/10/16 Javascript
js打造数组转json函数
2015/01/14 Javascript
Javascript核心读书有感之语言核心
2015/02/01 Javascript
javascript实现数字倒计时特效
2016/03/30 Javascript
浅谈js在html中的加载执行顺序,多个jquery ready执行顺序
2016/11/26 Javascript
详解nodejs 文本操作模块-fs模块(三)
2016/12/22 NodeJs
基于Bootstrap下拉框插件bootstrap-select使用方法详解
2018/08/07 Javascript
使用vue-cli3新建一个项目并写好基本配置(推荐)
2019/04/24 Javascript
Vue实现仿iPhone悬浮球的示例代码
2020/03/13 Javascript
[06:24]DOTA2亚洲邀请赛小组赛第三日 TOP10精彩集锦
2015/02/01 DOTA
Python中处理unchecked未捕获异常实例
2015/01/17 Python
python实现微信跳一跳辅助工具步骤详解
2018/01/04 Python
Python3实现的Mysql数据库操作封装类
2018/06/06 Python
python获取地震信息 微信实时推送
2019/06/18 Python
Python3.7 pyodbc完美配置访问access数据库
2019/10/03 Python
主要的Ajax框架都有什么
2013/11/14 面试题
高二政治教学反思
2014/02/01 职场文书
英语自我介绍演讲稿
2014/09/01 职场文书
党委干部批评与自我批评发言稿
2014/09/28 职场文书
流动人口婚育证明
2014/10/19 职场文书
2014最新自愿离婚协议书范本
2014/11/19 职场文书
2014年团总支工作总结
2014/11/21 职场文书
2015年安全生产月活动总结
2015/03/26 职场文书
初中体育教学随笔
2015/08/15 职场文书
《鲁滨逊漂流记》之六读后感(4篇)
2019/09/29 职场文书
oracle数据库去除重复数据
2022/05/20 Oracle