JavaScript插件化开发教程(六)

一,开篇分析

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

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多选模式,现在只是默认下拉模式。

看我本文,是不是要比上一篇代码优秀了很多呢,小伙伴们自己做项目也应该多想多做,尽量使自己的代码更加的合理。

(0)

相关推荐

  • JavaScript插件化开发教程 (二)

    一,开篇分析 Hi,大家好!还记得前面的那篇文章吗------这个系列的开篇(JavaScript插件化开发教程一).主要讲述了以"jQuery的方式如何开发插件", 那么今天我们带着昨天的疑问来继续我们的插件开发之旅.之前的问题如下: (1),如果项目技术选型换了这些插件又是强依赖"jQuery"机制,我们以前写的插件将会不能用(假设不用jQuery的情况),如何做重构那? (2),重构插件的关键逻辑,我们将如何组织那? 好了,带着问题去学习今天的文章吧. 首先我

  • JavaScript插件化开发教程 (三)

    一,开篇分析 前面两篇文章我们主要讲述了以"jQuery的方式如何开发插件",以及过程化设计与面向对象思想设计相结合的方式是 如何设计一个插件的,两种方式各有利弊取长补短,本系列文章是以学习为导向的,具体场景大家自己定夺使用方式.那么今天从这篇文章开始,我们就以实例的方式带着大家由浅入深的开发属于自己的插件库.嘿嘿嘿,废话少说,进入正题.直接上实际效果图: 大家看到了吧,这是一个选项卡插件,在我们日常做那种单页应用("SPA")的时候或许会接触到,就拿今天的例子来说

  • Android笔记之:App应用之启动界面SplashActivity的使用

    当前比较成熟一点的应用基本上都会在进入应用之显示一个启动界面.这个启动界面或简单,或复杂,或简陋,或华丽,用意不同,风格也不同.下面来观摩几个流行的应用的启动界面. 1. 货比三家以腾讯qq,新浪weibo,UC浏览器,游戏神庙逃亡等7个应用为例,比比看:(我认为最精美的界面应该是qq2012,虽然只有一张图,基本的应用名称,版本,图标这些信息都有,但是看着舒服,觉得美.) 2. 元素启动界面的本意是以友好用户界面来掩饰后台缓冲加载,让用户用平和等待的心情进入正常应用界面.但是因为启动界面是放在

  • Android中利用App实现消息推送机制的代码

    1.消息推送机制 服务器器端需要变被动为主动,通知客户一些开发商认为重要的信息,无论应用程序是否正在运行或者关闭. 我想到了一句话:don't call me,i will call you! qq今天在右下角弹出了一个对话框:"奥巴马宣布本拉登挂了...",正是如此. 自作聪明,就会带点小聪明,有人喜欢就有人讨厌. 2.独立进程 无论程序是否正在运行,我们都要能通知到客户,我们需要一个独立进程的后台服务. 我们需要一个独立进程的后台服务. 在androidmanifest.xml中注

  • 一看就懂的Android APP开发入门教程

    工作中有做过手机App项目,前端和android或ios程序员配合完成整个项目的开发,开发过程中与ios程序配合基本没什么问题,而android各种机子和rom的问题很多,这也让我产生了学习android和ios程序开发的兴趣.于是凌晨一点睡不着写了第一个android程序HelloAndroid,po出来分享给其他也想学习android开发的朋友,这么傻瓜的Android开发入门文章,有一点开发基础的应该都能看懂. 一.准备工作 主要以我自己的开发环境为例,下载安装JDK和Android SD

  • Android 避免APP启动闪黑屏的解决办法(Theme和Style)

    前几天Boss就反应说,机器每次启动程序都会闪一下黑屏,这个客户不接受.没办法,只能想想怎么解决,最后找到了下面的方法.闪黑屏的原因主要是我们启动Activity的时候,需要跑完onCreate和onResume才会显示界面.也就是说需要处理一些数据后,才会显示.按照这种思路,是不是我把初始化的工作尽量减少就可以避免黑屏?事实是,就算你onCreate啥都不做,仍然会闪一下黑屏,因为初始化解析界面时需要一定时间.下面是解决办法:1.自定义Theme 复制代码 代码如下: 设置背景图Theme<s

  • JavaScript插件化开发教程(五)

    一,开篇分析 Hi,大家好!前两篇文章我们主要讲述了以"jQuery的方式如何开发插件",以及过程化设计与面向对象思想设计相结合的方式是如何设计一个插件的,两种方式各有利弊取长补短,嘿嘿嘿,废话少说,进入正题.直接上实际效果图: 大家看到了吧,这是一个下拉菜单插件,在我们日常开发中,系统提供的可能有时让我们觉得不是很美观并且功能有限,造成用户 的体验形式以及用户的可交互性不是很好,所以今天模拟一个嘿嘿嘿.下面就具体分析一下吧. (二),实例分析 (1),首先确定这个插件做什么事.下面看

  • JavaScript插件化开发教程 (一)

    一,开篇分析 Hi,大家!今天这系列文章主要是说说如何开发基于"JavaScript"的插件式开发,我想很多人对"插件"这个词并不陌生, 有的人可能叫"组件"或"部件",这不重要,关键是看如何设计,如何做一个全方位的考量,这是本文的重点阐述的概念.我想大家对 "jQuery插件的方式"有一定的了解,我们结合这个话题一起讨论一下,最终给出相关的实现方案,来不断提高自己的谁能力. 二,进入插件正题 一般来说,j

  • 亲自动手实现Android App插件化

    Android插件化目前国内已经有很多开源的工程了,不过如果不实际开发一遍,很难掌握的很好. 下面是自己从0开始,结合目前开源的项目和博客,动手开发插件化方案. 按照需要插件化主要解决下面的几种问题: 1. 代码的加载 (1) 要解决纯Java代码的加载 (2) Android组件加载,如Activity.Service.Broadcast Receiver.ContentProvider,因为它们是有生命周期的,所以要特殊处理 (3) Android Native代码的加载 (4) Andro

  • JavaScript插件化开发教程 (四)

    一,开篇分析 Hi,还记得上一篇文章吗.主要讲述了一个"Tab"插件是如何组织代码以及实现的",以及过程化设计与面向对象思想设计相结合的方式是 如何设计一个插件的,两种方式各有利弊取长补短,本系列文章是以学习为导向的,具体场景大家自己定夺使用方式.在从这篇文章中,我们还是以那个"Tab"实例为主, 继续扩展相关功能.嘿嘿嘿,废话少说,进入正题.直接上实际效果图: 大家看到了吧,增加了一个新的功能,如果我们在初始化时,我们的模块配置信息项目的条目数大于我们指

随机推荐