大熊君JavaScript插件化开发------(第二季)
一,开篇分析
Hi,大家好!大熊君又和大家见面了,还记得昨天的那篇文章吗------这个系列的开篇(第一季)。主要讲述了以“jQuery的方式如何开发插件”,
那么今天我们带着昨天的疑问来继续我们的插件开发之旅。昨天的问题如下:
(1),如果项目技术选型换了这些插件又是强依赖“jQuery”机制,我们以前写的插件将会不能用(假设不用jQuery的情况),如何做重构那?
(2),重构插件的关键逻辑,我们将如何组织那?
好了,带着问题去学习今天的文章吧。
首先我不是否定“jQuery插件的方式”,其次是我们要从不同的角度分析问题,比如说“jQuery插件有如下优点”:
(1),把全部代码放在闭包(一个即时执行函数)里此时闭包相当于一个私有作用域,外部无法访问到内部的信息,并且不会存在全局变量的污染情况。
(2),a) 避免全局依赖;b) 避免第三方破坏;c) 兼容jQuery操作符'$'和'jQuery '。
那我们重构将以什么方式组织代码那,是面向对象的思想(OOP)那?还是过程化的思路进行到底那?还是两者结合设计那?哈哈哈,继续看。。。。。。
二,重构昨天的例子
以下是昨天的Js部分源码部分:
1 (function($){ 2 $.fn.bigbear = function(opts){ 3 opts = $.extend({},$.fn.bigbear.defaults,opts) ; 4 return this.each(function(){ 5 var elem = $(this) ; 6 elem.find("span").text(opts["title"]) ; 7 $.get(opts["url"],function(data){ 8 elem.find("div").text(data["text"]) ; 9 }) ; 10 }) ; 11 } ; 12 $.fn.bigbear.defaults = { 13 title : "这是一个简单的测试" , 14 url : "data.json" 15 } ; 16 })(jQuery) ;
我们来逐行分析一下:
首先确定一下这个插件的功能
(1),显示我们设置的标题文字信息。
(2),动态通过异步的方式获取内容信息。
好了!需求明确就好展开讨论了,从上面的代码不难看出逻辑组织很松散,过程化的思维很明显,所以第一步就是把我们的功能需求
以类的方式有效地组织起来。看如下重构后的代码:
1 $(function(){ 2 $("#bb").bigbear() ; 3 }) ; 4 (function($){ 5 $.fn.bigbear = function(opts){ 6 opts = $.extend({},$.fn.bigbear.defaults,opts) ; 7 return this.each(function(){ 8 var elem = $(this) ; 9 var bb = new BigBear(elem,opts) ; 10 bb.getElem().trigger("data") ; 11 }) ; 12 } ; 13 $.fn.bigbear.defaults = { 14 title : "这是一个简单的测试" , 15 url : "data.json" 16 } ; 17 })(jQuery) ; 18 19 function BigBear(elem,opts){ 20 this.elem = elem ; 21 this.opts = opts ; 22 this.init() ; 23 } ; 24 var bbProto = BigBear.prototype ; 25 bbProto.getElem = function(){ 26 return this.elem ; 27 } ; 28 bbProto.getOpts = function(){ 29 return this.opts ; 30 } ; 31 bbProto.init = function(){ 32 var that = this ; 33 this.getElem().on("data",function(){ 34 that._setTitle(that.getOpts()["title"]) ; 35 $.get(that.getOpts()["url"],function(result){ 36 that.getElem().find("div").text(result["text"]) ; 37 }) ; 38 }) ; 39 } ; 40 bbProto._setTitle = function(text){ 41 this.getElem().find("span").text(text) ; 42 } ;
哈哈哈,是不是代码多了不少,其实这种方式就是面向对象的角度看问题,先去分析功能需求,然后设计我们的类,虽然说我们不可能一下设计得很出色,
但是看问题角度改变了,我们的代码可读性强了,以及更好地进行维护这样我们的目的也就达到了。
以下是是摘自“Bootstrap”Js部分的相关源码实现,如下图:
不难看出也是相似的实现方式,通过类来维护我们插件的主要逻辑。
(三),增加新功能,引出额外的类
现在需求增加了,需要在体验上有所变化,加载数据时有“loading”效果。
实现思路可以这样,在原始的内容区把文字设置成“装载数据中。。。。”的字样,然后引入一个新的类,如下:
1 function Overlay(){ 2 3 } ; 4 var olProto = Overlay.prototype ; 5 olProto.show = function(){} ; 6 olProto.hide = function(){} ; 7 // 具体实现就不写了
好了,遮罩层已经有了,现在我们怎么集成进来那?我们用组合的方式接入进来,如下:
1 function BigBear(elem,opts){ 2 this.elem = elem ; 3 this.opts = opts ; 4 this.overlay = new Overlay() ; 5 this.init() ; 6 } ; 7 var bbProto = BigBear.prototype ; 8 bbProto.getElem = function(){ 9 return this.elem ; 10 } ; 11 bbProto.getOpts = function(){ 12 return this.opts ; 13 } ; 14 bbProto.init = function(){ 15 var that = this ; 16 var loadingText = "数据装载中。。。" ; 17 this.getElem().on("data",function(){ 18 that._setTitle(that.getOpts()["title"]) ; 19 that.overlay.show() ; 20 that.getElem().find("div").text(loadingText) ; 21 $.get(that.getOpts()["url"],function(result){ 22 that.overlay.hide() ; 23 that.getElem().find("div").text(result["text"]) ; 24 }) ; 25 }) ; 26 } ; 27 bbProto._setTitle = function(text){ 28 this.getElem().find("span").text(text) ; 29 } ;
到此只为我们的功能就算是结束了,这样写的插件,我相信比第一个版本好很多,当然这不是最优的实现,需要从细节上不断重构,但是这种方式是一种可选的开发插件的方式。
以下是完整的代码:
1 $(function(){ 2 $("#bb").bigbear() ; 3 }) ; 4 (function($){ 5 $.fn.bigbear = function(opts){ 6 opts = $.extend({},$.fn.bigbear.defaults,opts) ; 7 return this.each(function(){ 8 var elem = $(this) ; 9 var bb = new BigBear(elem,opts) ; 10 bb.getElem().trigger("data") ; 11 }) ; 12 } ; 13 $.fn.bigbear.defaults = { 14 title : "这是一个简单的测试" , 15 url : "data.json" 16 } ; 17 })(jQuery) ; 18 19 function BigBear(elem,opts){ 20 this.elem = elem ; 21 this.opts = opts ; 22 this.overlay = new Overlay() ; 23 this.init() ; 24 } ; 25 var bbProto = BigBear.prototype ; 26 bbProto.getElem = function(){ 27 return this.elem ; 28 } ; 29 bbProto.getOpts = function(){ 30 return this.opts ; 31 } ; 32 bbProto.init = function(){ 33 var that = this ; 34 var loadingText = "数据装载中。。。" ; 35 this.getElem().on("data",function(){ 36 that._setTitle(that.getOpts()["title"]) ; 37 that.overlay.show() ; 38 that.getElem().find("div").text(loadingText) ; 39 $.get(that.getOpts()["url"],function(result){ 40 that.overlay.hide() ; 41 that.getElem().find("div").text(result["text"]) ; 42 }) ; 43 }) ; 44 } ; 45 bbProto._setTitle = function(text){ 46 this.getElem().find("span").text(text) ; 47 } ; 48 49 function Overlay(){ 50 51 } ; 52 var olProto = Overlay.prototype ; 53 olProto.show = function(){} ; 54 olProto.hide = function(){} ; 55 // 具体实现就不写了
(四),最后总结
(1),面向对象的思考方式合理分析功能需求。
(2),以类的方式来组织我们的插件逻辑。
(3),不断重构上面的实例,最好自己写一下,并且完善“Overlay”的逻辑。
(4),大家学习完继续思考一下,如何进行合理的重构那?不要设计过度,要游刃有余,推荐的方式是过程化设计与面向对象思想设计相结合。
哈哈哈,本篇结束,未完待续,希望和大家多多交流够沟通,共同进步。。。。。。呼呼呼……(*^__^*)