原生Javascript插件封装开发实践

前言

之前公司设计的网站比较混乱,很多地方不统一,其中一个就是弹出层,导致这个原因是因为,公司的UI换了好几个人,而他们每个人做出来的都不太一样。最近公司开始整顿这个问题,对于统一的这种东西当然是做成一个模块,或者插件,而我打算做成插件。之所以写这篇文章是因为,当写完这个插件以后,发现其中有不少的理念,而这些理念我想把它总结一下,虽然这个插件并不复杂。

该怎样架构?

对于架构这个概念,接触的比较少,我的理解,架构就是解决未来可能会发生的事。

之前也封装过一些插件,但后端嫌我封装的太难用,于是分析其原因,发现之前写的插件,该暴露的接口没有,有些不需要传的参数反而要传。该暴露的接口没有,这是因为我没有按照未来的思想来写插件,而往往这样写出来的插件就成了一次性用品。

所以这段时间,在写插件之前都会事先思考清楚,这个插件都需要哪些参数,而哪些又是必须传的,哪些是可选的,哪些功能以后可能会用到,哪些是可以会更改的,这些都是必须考虑的,不然写出来的插件肯定会有很多的问题。

基本雏形

[javascript]  view plain  copy
  1. (function(window,document){  
  2.     var MaskShare = function(){  
  3.   
  4.     };  
  5.     MaskShare.prototype = {};  
  6.   
  7.     window.MaskShare = MaskShare;  
  8. }(window,document));  

把要写的代码,封闭到一个自执行函数里面,防止变量冲突,然后将这个构造函数暴露给window对象,方便我们在外部去访问这个构造函数。

效果需要做成如下的:


思考需要哪些参数

这个功能就是点击某个元素,弹出一个遮罩层,点击遮罩层将遮罩层去掉。

因此可以分析出,至少需要一个参数,也就是我们需要知道点击谁弹出弹出层,另外我们还需要配置一些默认参数。

[javascript]  view plain  copy
  1. (function(window,document){  
  2.     var MaskShare = function(targetDom,options){  
  3.         // 判断是用函数创建的还是用new创建的。这样我们就可以通过MaskShare("dom") 或 new MaskShare("dom")来使用这个插件了  
  4.         if(!(this instanceof MaskShare))return new MaskShare(targetDom,options);  
  5.   
  6.         // 参数合并  
  7.         this.options = this.extend({  
  8.                         // 这个参数以后可能会更改所以暴露出去  
  9.             imgSrc:"../static/img/coupon-mask_1.png"  
  10.         },options);  
  11.   
  12.         // 判断传进来的是DOM还是字符串  
  13.         if((typeof targetDom)==="string"){  
  14.             this.targetDom = document.querySelector(targetDom);  
  15.         }else{  
  16.             this.targetDom = targetDom;  
  17.         }  
  18.   
  19.         var boxDom = document.createElement("div");  
  20.         var imgDom = document.createElement("img");  
  21.   
  22.         // 设置默认样式 注意将z-index值设置大一些,防止其他元素层级比遮罩层高  
  23.         boxDom.style.cssText = "display: none;position: absolute;left: 0;top: 0;width: 100%;height:100%;background-color: rgba(0,0,0,0.8);z-index:9999;";  
  24.         imgDom.style.cssText = "margin-top:20px;width: 100%;";  
  25.   
  26.         // 追加或重设其样式  
  27.         if(this.options.boxDomStyle){  
  28.             this.setStyle(boxDom,this.options.boxDomStyle);  
  29.         }  
  30.         if(this.options.imgDomStyle){  
  31.             this.setStyle(imgDom,this.options.imgDomStyle);  
  32.         }  
  33.   
  34.         imgDom.src = this.options.imgSrc;  
  35.         boxDom.appendChild(imgDom);  
  36.         this.boxDom = boxDom;  
  37.   
  38.         // 初始化  
  39.         this.init();  
  40.     };  
  41.     MaskShare.prototype = {  
  42.         init:function(){  
  43.             this.event();  
  44.         },  
  45.         extend:function(obj,obj2){  
  46.             for(var k in obj2){  
  47.                 obj[k] = obj2[k];  
  48.             }  
  49.             return obj;  
  50.         },  
  51.         setStyle:function(dom,objStyle){  
  52.             for(var k in objStyle){  
  53.                 dom.style[k] = objStyle[k];  
  54.             }  
  55.         },  
  56.         event:function(){  
  57.             var _this = this;  
  58.   
  59.             this.targetDom.addEventListener("click",function(){  
  60.                 document.body.appendChild(_this.boxDom);  
  61.                 _this.boxDom.style.display = "block";  
  62.                                 // 打开遮罩层的回调  
  63.                 _this.options.open&&_this.options.open();  
  64.             },false);  
  65.   
  66.             this.boxDom.addEventListener("click",function(){  
  67.                 this.style.display = "none";  
  68.                                 // 关闭遮罩层的回调  
  69.                 _this.options.close&&_this.options.close();  
  70.             },false);  
  71.         }  
  72.     };  
  73.     // 暴露方法  
  74.     window.MaskShare = MaskShare;  
  75. }(window,document));  

使用示例:

[html]  view plain  copy
  1. MaskShare(".immediately",{  
  2.     imgSrc:"../static/img/loading_icon.gif",  
  3.     boxDomStyle:{  
  4.         opacity:".9"  
  5.     },  
  6.     imgDomStyle:{  
  7.         opacity:".8"  
  8.     },  
  9.     open:function(){  
  10.         console.log("show");  
  11.     },  
  12.     close:function(){  
  13.         console.log("close");  
  14.     }  
  15. });  、
  16. 由于项目原因,工作一年多还没用js写过插件,项目太成熟,平时基本都是在使用已经封装好的功能插件。感觉自己好low......这两天想自己抽空写一个canvas画统计图与折现图的插件,所以就去网上学习了下如何封装.....虽然之前看了很多源码,但是感觉就算了解也是野路子.....

    什么是封装呢?

    我的理解就是 把一个功能单独做成一个组件,就像做饺子,以前做饺子必须自己先用面粉做饺子皮,再做饺子馅,然后再手工包饺子,但是现在人们发明了自动包饺子机器,虽然机器里面的每一步骤和你自己包饺子是一样的,但是实际上你现在需要做的就只有一件事,就是放原料。这边机器就是封装好的插件,而原料就是你要传的参数

    为什么要把js功能封装成插件呢?我觉得有以下几点吧

      1、便于代码复用

      2、避免各个相同功能组件的干扰,可能会有作用域的一些问题吧

      3、便于维护,同时利于项目积累

      4、不觉得一直复制粘贴很low么.......

    我在网上看到的封装好像有两种,一种是js的原生封装,一种是jquery的封装。这边我先讲一下原生封装吧。

    我们在封装的时候会把js代码放到一个自执行函数里面,这样可以防止变量冲突。

    ?
    1
    2
    3
    4
    5
    6
    7
    ( function (){
     
       ......
     
       ......
     
    }()}

    然后再创建一个构造函数

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ( function (){
     
       var demo = function (options){
     
         ......
     
       }
     
    }())

    把这个函数暴露给外部,以便全局调用

    ?
    1
    2
    3
    4
    5
    6
    ( function (){
       var demo = function (options){
         ......
       }
       window.demo = demo;
    }())

    其实现在你可以直接调用了,封装好了,虽然没实现什么功能

    ?
    1
    2
    3
    4
    var ss = new demo({
       x:1,
       y:2
    });

    或者

    ?
    1
    2
    3
    4
    new demo({
       x:2,
       y:3
    });

    然后传参怎么搞呢,我们一个插件一般有一些必选参数或者可选参数,在我看来可选参数不过就是在插件里面给了默认值罢了。我们传的参数会覆盖插件中的默认参数,可以用$.extend({})覆盖

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    ( function (){
     
       var demo = function (options){
     
         this .options = $.extend({
     
           "x" : 1,
     
           "y" : 2,
     
           "z" : 3
     
         },options)
     
       }
     
       window.demo = demo;
     
    }())

    然后你可以在在初始化构造函数的时候执行一些操作

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    ( function (){
       var demo = function (options){
         this .options = $.extend({
           "x" : "1" ,
           "y" : "2" ,
           "z" : "3"
         },options);
         this .init();
       };
       demo.prototype.init = function (){
         alert( "x是" + this .options.x+ " y是" + this .options.y+ " z是" + this .options.z);
       };
       window.demo = demo;
    }());
    new demo({
       "x" : "5" ,
       "y" : "4"
    });
    </script>

    就是这样了。一个超级简单的封装

     

    我这边有个疑问,extend只是jquery有吗,js对象有什么代替方法吗?晚点在看看............. 

    还有需要提的是封装js的时候我们要考虑周全,比如它的扩展性和兼容性,还有性能怎么样,还有没必要的就不需要封装了......要有选择性。

    现在网上已经完成的插件数不胜数,而且功能又十分强大,但是恰恰是这点,有的时候一个很大的插件我们只用到很小的一部分,那么就需要我们自己修改成适合我们自己的了,而且有些项目的风格和现在的插件风格也不同,所以关键是要适合自己的项目。


猜你喜欢

转载自blog.csdn.net/hahahhahahahha123456/article/details/80211263