TMaize Blog

原生js插件封装

在进行开发时,有时候需要一个小功能(比如jsonp),但是却有一个很大的库(jQuery)提供了这个功能。

为了保证代码的简洁性,肯定是打算自己造轮子,下面是进行原生JavsScript插件的一些步骤

要求

首先一个合格的插件要有下面几个要求

步骤

显然,把所有功能都写在一个单纯的函数内是无法满足上述要求的

插件全局函数

实现私有作用域,最好的办法就是使用闭包。可以把插件当做一个函数,插件内部的变量及函数的私有变量,为了在调用插件后依旧能使用其功能,闭包的作用就是延长函数(插件)内部变量的生命周期,使得插件函数可以重复调用,而不影响用户自身作用域。

故需将插件的所有功能写在一个立即执行函数中:

(function () {
	//插件所有功能都写在这个函数下
})();

插件默认参数

插件的主要功能可以总结至几个关键参数,通过这几个关键参数即可修改插件的主要功能,也是第三步API设置的关键参数。

将默认参数放置在全局函数的最前面,参数变量名为options,通过对象字面量进行赋值:

var options = {
	key1: para1,
	key2: para2,
	key3: para3,
	...
	keyn: paran
}

插件API、参数设置和监听

因为API指向的是使用者,故需要在用户调用插件时将API暴露给用户,因用户API时是通过插件提供的名字进行使用,故将API设置为Object类型,用户就可以通过调用API的key进行使用,具体的代码如下:

var api = {
	config: function (ops) {
		//....
		return this;//便于链式调用
	},
	listen: function listen(elem) {
		//...
		return this;
	},
	feature1: function() {
		//...
	},
	feature2: function() {
		//...
	}
}
this.pluginName = api;

代码框架

根据上述步骤

;(function () {
    
    //配置-私有的
	var options = {
        ....
	}

    //私有的函数,供内部调用
	function doSomething() {
		...
	}

	//API
	var api = {
        //配置参数
		config: function (opts) {
			if(!opts) return options;
			for(var key in opts) {
				options[key] = opts[key];
			}
			return this;
		},
        //设置监听
		listen: function listen(elem) {
			if (typeof elem === 'string') {
				var elems = document.querySelectorAll(elem),
					i = elems.length;
					while (i--) {
						listen(elems[i]);
					}
					return
			}
            //调用内部的函数
			doSomething(elem, options.splitter);

			return this;
		}
	}
	//this==window
	this.myplugin = api;
})();

对象

当然了,通过对象的创建也能很好的实现上述的效果

一般情况下,闭包函数写的插件的配置是config之后是公共的了,多次调用插件用的是同一个配置

如果需要手动的对element添加不同的配置的推荐使用对象的方式创建,new对象是传入不同的配置,再把对象应用于不同的element

总之闭包函数写的插件体现在公用,通过对象写的插件体现在私用,比如分页插件,一个页面可能有多个分页插件,采用不同的配置,不同的监听效果,,用该使用多个对象才能对多个分页插件进行互不干扰的操作

DEMO

下面是一个简单的jsonp插件代码

;(function () {

    //主要函数
    function main(options,callbackfunc){

        //产生一个随机函数名
        var callbackName = ('jsonp_' + Math.random()).replace(".", "");

        //参数添加到url中
        var newUrl = addUrlParm(options.url,options.parm);
        if(!newUrl.endsWith('?')){
            newUrl = newUrl+"&";
        }
        newUrl=newUrl+options.callbackName+"="+callbackName;
        
        //创建 script 标签并加入到页面中
        var oHead = document.getElementsByTagName('head')[0];
        var oS = document.createElement('script');
        oHead.appendChild(oS);
        
        //创建jsonp回调函数
        window[callbackName] = function (json) {
            oHead.removeChild(oS);
            clearTimeout(oS.timer);
            window[callbackName] = null;
            callbackfunc(json);
        };

        //超时处理
         oS.timer = setTimeout(function () {
            window[callbackName] = null;
            oHead.removeChild(oS);
            callbackfunc(null);
        }, options.time);

        //开始请求
        oS.src = newUrl;
    }

    function addUrlParm(url,parm){
        var arr = [];
        for (var name in parm){
            arr.push(name + '=' + parm[name]);
        }
        return url+"?"+arr.join('&');
    }

    var api = {
        execute:function(opt,callbackfunc){
            options = {
                parm:{},
                time:3000,
                callbackName:'callback'
            };
            if (!opt.url&&!opt.callback) {
                console.error("参数不合法....");
                return;
            }else{
                options.url=opt.url;
            }
            options.parm=opt.parm||options.parm;
            options.time=opt.time||options.time;
            options.callbackName=opt.callbackName||options.callbackName;
            main(options,callbackfunc);
        }
    };

    //曝露方法
    this.jsonp = api;
})();