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 贪吃蛇实现代码
Nov 22 Javascript
jquery 插件学习(一)
Aug 06 Javascript
Extjs中TabPane如何嵌套在其他网页中实现思路及代码
Jan 27 Javascript
node.js中的fs.unlinkSync方法使用说明
Dec 15 Javascript
BOM系列第三篇之定时器应用(时钟、倒计时、秒表和闹钟)
Aug 17 Javascript
Bootstrap modal 多弹窗之叠加引起的滚动条遮罩阴影问题
Feb 27 Javascript
关于Vue中axios的封装实例详解
Oct 20 Javascript
基于JS实现视频上传显示进度条
May 12 Javascript
Js数组扁平化实现方法代码总汇
Nov 11 Javascript
微信小程序自定义底部弹出框动画
Nov 18 Javascript
Vue使用Element实现增删改查+打包的步骤
Nov 25 Vue.js
详解如何在Canvas中添加事件的方法
Apr 17 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如何调用webservice应用介绍
2012/11/24 PHP
使用PHP导出Redis数据到另一个Redis中的代码
2014/03/12 PHP
解决出现SoapFault (looks like we got no XML document)的问题
2017/06/24 PHP
PHP实现的只保留字符串首尾字符功能示例【隐藏部分字符串】
2019/03/11 PHP
Exitjs获取DataView中图片文件名
2009/11/26 Javascript
基于dom编程中 动态创建与删除元素的使用
2013/04/17 Javascript
js/html光标定位的实现代码
2013/09/23 Javascript
理解javascript对象继承
2016/04/17 Javascript
详解JavaScript中Hash Map映射结构的实现
2016/05/21 Javascript
javascript实现的左右无缝滚动效果
2016/09/19 Javascript
vue开发心得和技巧分享
2016/10/27 Javascript
手把手教你搭建ES6的开发运行环境
2017/07/11 Javascript
JavaScript基于activexobject连接远程数据库SQL Server 2014的方法
2017/07/12 Javascript
JavaScript事件对象event用法分析
2018/07/27 Javascript
解决angularjs WdatePicker ng-model的问题
2018/09/13 Javascript
vue实现压缩图片预览并上传功能(promise封装)
2019/01/10 Javascript
js实现无缝滚动双图切换效果
2019/07/09 Javascript
vue+axios全局添加请求头和参数操作
2020/07/24 Javascript
Python数据分析之双色球统计单个红和蓝球哪个比例高的方法
2018/02/03 Python
Python爬虫的两套解析方法和四种爬虫实现过程
2018/07/20 Python
对numpy中的where方法嵌套使用详解
2018/10/31 Python
python opencv摄像头的简单应用
2019/06/06 Python
python实现按键精灵找色点击功能教程,使用pywin32和Pillow库
2020/06/04 Python
python实现图像高斯金字塔的示例代码
2020/12/11 Python
L*SPACE官网:比基尼、泳装和度假服装
2019/03/18 全球购物
新加坡第一的杂货零售商:NTUC FairPrice
2020/12/05 全球购物
物业经理求职自我评价
2013/09/22 职场文书
前台接待岗位职责
2013/12/03 职场文书
实习单位接收函模板
2014/01/10 职场文书
交通局领导班子群众路线教育实践活动对照检查材料思想汇报
2014/10/09 职场文书
运动会广播稿200字(10篇)
2014/10/12 职场文书
考研英语复习计划
2015/01/19 职场文书
党内外群众意见范文
2015/06/02 职场文书
公司出差管理制度范本
2015/08/05 职场文书
2016年质量月活动总结报告
2016/04/05 职场文书
老生常谈 使用 CSS 实现三角形的技巧(多种方法)
2021/04/13 HTML / CSS