zoukankan      html  css  js  c++  java
  • js插件动态加载js、css解决方案

      最近因为工作需要做了一个js自动导入的插件,一开始很天真的以为动态创建个script添加到head中就ok了,试了之后才发现了问题,就是如果同时引入了多个js文件,而且后一个文件中用到了前一个文件中的变量,那就会报错,靠~~悲催了,就是说js如果动态加载(非浏览器加载因为浏览器加载时同步加载的会等待前一个js加载完成后才进行下一个js加载,这样就不会出现问题)那加载的文件是异步进行的,难怪啊!然后在网上找了些资料说用ajax同步加载,然后我试了真可以,下面就是我的代码分享出来给大家,但是注意这样加载出来的js有一个致命的弱点,就是没法再浏览器上调试- - !!!!!以后再寻找解决方案吧,先贴代码:

    js主文件importComJs.js:

    **
     * Created by carlos on 2015/5/19.
     * QImport 导入帮助函数,可以很方便的导入指定的js、css文件。但是需要注意的是,这样导入的js将无法调试,暂时没有找到解决方案--!
     * 使用方法先把此文件引入,必须放在head中的最前面导入,
     * <script src="../js/importComJs.js" id="QImport"></script>
     * id必须是QImport,否则无效
     * 然后加入
     * <script>
     * 	 	QImport.init(customscripts);
     * </script>
     * customscripts参数为:外加的引入文件配置,可以不填。但填写必须遵守QImport.IMPORTSCRIPTS的写法。
     * 如果不想手动初始化引入函数,可以这样写:
     * <script src="../js/importComJs.js" id="QImport" data-auto="true"></script>
     * 这里的 data-auto为true时候才会自动初始化,否则需要手动初始化。
     * 使用上自动初始化,不用担心引入顺序问题,后面的其他js、css文件按正常引用就可以了。
     * 注意:importComjs文件必须第一个引入,否则将出现引用找不到的问题。
     * 新增属性:
     * 		data-config:自定义配置文件名,默认为“importConfig.json”
     * 		data-personalconfigname:自定义个性化配置名称,在配置文件中的“personalscripts”中配置
     * 		注意:配置加载顺序是:importscripts最高、personalscripts其次、customscripts最低。如果引入的次序不对会引起空指针报错哦^^!
     */
    
    /**
     * 同步加载js脚本
     * @param id   需要设置的<script>标签的id
     * @param url   js文件的相对路径或绝对路径
     * @return {Boolean}   返回是否加载成功,true代表成功,false代表失败
     */
    (function(){
    	QImport = {
    		self:{
    			obj:function(){
    				return document.getElementById('QImport');      //获取script的id,如果项目中实在是有冲突不得不改,那就该这个“QImport”吧!
    			},
    			auto:function(){
    				return eval(this.getAttr('data-auto'));   		//是否开启自动初始化模式,默认为false
    			},
    			config:function(){
    				return this.getAttr('data-config');       		//自定义配置文件名,默认为“importConfig.json”
    			},
    			personal:function(){
    				return this.getAttr('data-personalconfigname')  //自定义个性化配置名称,在配置文件中的“personalscripts”中配置。
    			},
    			src:function(){
    				return this.getAttr('src');                     //此文件位置,不多说
    			},
    			getAttr:function(attrName){
    				var attrValue = undefined;
    				try{
    					attrValue = this.obj().getAttribute(attrName);
    				}
    				catch(e){}
    				return attrValue;
    			},
    			relationpath:function(){
    				var src = this.src();
    				var re = /^[../]*/;
    				return src.match(re)[0];
    			},
    			path:function(filename){
    				var src = this.src();
    				var temp = src.split('/');
    				var path = "";
    				temp.pop();
    				temp.push(filename);
    				return temp.join('/');
    			}
    		},
    		autoinit:function(){
    			if(this.self.auto()){
    				this.init(); 
    			}
    		},
    		getpath:function(p){
    			var path = this.self.relationpath()+p;
    			return path.replace('//','/'); 
    		},
    		init:function(customscripts){						//导入文件的主方法
    			this.extend(customscripts);
    			var IMPORTSCRIPTS = this.IMPORTSCRIPTS;
    			var head = document.getElementsByTagName("head").item(0);
    			var meta = document.createElement('meta');  //自动添加web手机适应代码;
    			meta.name = 'viewport';
    			meta.content = 'width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no';
    			head.insertBefore(meta, head.childNodes[0]);
    			var re = /^http[s]?:///i;
    			for(var i=0;i<IMPORTSCRIPTS.length;i++){  
    				loadpath = IMPORTSCRIPTS[i].url; 
    				if(!re.test(IMPORTSCRIPTS[i].url)){
    					loadpath = this.getpath(IMPORTSCRIPTS[i].url);
    				}
    				if(IMPORTSCRIPTS[i].type=="script"){
    					var flag = this.loadJS(loadpath,loadpath,i+1)
    					if(!flag){
    						alert('loading path:"'+loadpath+'" failed,May be lost "http(s)://"');
    					}	
    				}
    				else if(IMPORTSCRIPTS[i].type=="css"){
    					var csss = document.createElement('link')
    					csss.href = this.getpath(IMPORTSCRIPTS[i].url);
    					csss.rel = 'stylesheet';
    					head.insertBefore(csss, head.childNodes[i+1]); 
    				} 
    			}
    		},
    		extend:function(customscripts){                              //自定义扩展方法,仅适用当前对象
    			if(!(customscripts instanceof Array)) return;
    			var IMPORTSCRIPTS = this.IMPORTSCRIPTS;
    			for(var i=0;i<customscripts.length;i++){
    				var flag = false;
    				for(var j=0;j<IMPORTSCRIPTS.length;j++){
    					if((IMPORTSCRIPTS[j].type==customscripts[i].type)&&(IMPORTSCRIPTS[j].url==customscripts[i].url)){
    						flag = true;
    						break;
    					}
    				}
    				if(!flag){
    					this.IMPORTSCRIPTS.push({type:customscripts[i].type,url:customscripts[i].url});
    				}
    			}
    		},
    		ajax:function(url){                                     //ajax原始方法,这里仅可以同步请求
    			var  xmlHttp = null;
    		    if(window.ActiveXObject)//IE
    		    {
    		        try {
    		            //IE6以及以后版本中可以使用
    		            xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
    		        }
    		        catch (e) {
    		            //IE5.5以及以后版本可以使用
    		            xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    		        }
    		    }
    		    else if(window.XMLHttpRequest)//Firefox,Opera 8.0+,Safari,Chrome
    		    {
    		        xmlHttp = new XMLHttpRequest();
    		    }
    		    //采用同步加载
    		    xmlHttp.open("GET",url,false);
    		    //发送同步请求,如果浏览器为Chrome或Opera,必须发布后才能运行,不然会报错
    		    xmlHttp.send(null);
    		    //4代表数据发送完毕
    		    if ( xmlHttp.readyState == 4 ){
    		        //0为访问的本地,200到300代表访问服务器成功,304代表没做修改访问的是缓存
    		        if((xmlHttp.status >= 200 && xmlHttp.status <300) || xmlHttp.status == 0 || xmlHttp.status == 304){
    		            return xmlHttp.responseText;
    		        }
    		        else{
    		            return false;
    		        }
    		    }
    		    else{
    		        return false;
    		    }
    		},
    		loadJS:function(id,url,rank){								//加载js文件
    		    var importText = this.ajax(url);
    		    if(!importText) return false;
    		    var myHead = document.getElementsByTagName("HEAD").item(0);
    		    var myScript = document.createElement( "script" );
    		    myScript.language = "javascript";
    		    myScript.type = "text/javascript";
    		    myScript.id = id;
    		    try{
    		        //IE8以及以下不支持这种方式,需要通过text属性来设置 
    		        myScript.appendChild(document.createTextNode(importText));
    		    }
    		    catch (ex){
    		        myScript.text = importText;
    		    }
    		    myHead.insertBefore(myScript, myHead.childNodes[rank]);
    		    return true;
    		},
    		template:{								//加载模板文件,现在仅在引入“jquery”的情况下可用。			
    			parent:this,						//父类this引用				
    			_setparent:function(){				//把父类的this赋给子方法的parent
    				this.template.parent = this;
    			},
    			includeTagName:'include',           //引入时候用的标签:<include url="head.html"></include>
    			init:function(){
    				this.include();
    			},
    			include:function(){
    				var includes = document.getElementsByTagName(this.includeTagName);
    				for(var i=0;i<includes.length;i++){
    					var url = includes[i].getAttribute('url');
    					var includeHtml = this.parent.ajax(url);
    					var parent = includes[i].parentNode;
    					var newEs = this.parseDom(includeHtml);
    					for(var j=0;j<newEs.length;j++){
    						parent.insertBefore(newEs[j], includes[i])
    					}
    				}
    				while(true){
    					if(includes.length==0) break;
    					includes[0].remove();
    				}
    			},
    			parseDom:function(str){
    				var obj = document.createElement('div');
    				obj.innerHTML = str;
    				return obj.childNodes;
    			}
    		}, 
    		initparent:function(){              	//子类中想用父类中的方法必须通过此方法初始化以下,还必须引入如template的parent和_setparent
    			this.template._setparent.call(this);
    		},
    		getimportjson:function(){				//获取的配置json
    			var configName = this.self.config();            //共用配置
    			if(configName) this.configname = configName;
    			var configpath = this.self.path(this.configname); 
    			var confJsonStr = this.ajax(configpath);
    			if(!confJsonStr){
    				alert('config file path:"'+configpath+'" can not be loaded');
    				return;
    			}
    			this.confJson = eval('('+confJsonStr+')');
    			importarr = this.confJson.importscripts;
    			if(importarr instanceof Array){
    				this.IMPORTSCRIPTS = this.confJson.importscripts;
    			}
    			this.getpersonalarr();
    		},
    		getpersonalarr:function(){    			//获取个性化配置arr
    			var personalConfigName = this.self.personal();
    			if(!personalConfigName) return;
    			this.personalconfigname = personalConfigName;
    			var personalarr = this.confJson.personalscripts[personalConfigName];
    			if(personalarr instanceof Array){
    				this.extend(personalarr)
    			}
    		},
    		confJson:{},
    		IMPORTSCRIPTS:[],
    		configname:'importConfig.json'
    	}
    	QImport.getimportjson();
    	QImport.autoinit();
    	QImport.initparent();
    	try{
    		$(function(){
    			QImport.template.init();
    		});
    	}
    	catch(e){}
    	
    })();
    

    下面是配置文件,importConfig.json:

    {
    	importscripts:[
    		{
    			type: 'script',
    			url: 'js/jquery-1.9.1/jquery-1.9.1.min.js'
    		},{
    			type: 'script',
    			url: 'js/mui.min.js'
    		},{
    			type: 'css',
    			url: 'css/mui.min.css'
    		},{
    			type: 'script',
    			url: 'js/json2.js'
    		}
    	],
    	personalscripts:{
    		test:[
    			{
    				type:'script',
    				url:'js/test.js'
    			}
    		]
    	}
    }
    

    注意配置文件必须和导入方法js在同一个路径底下。

    以上就是我个人封装的引入js、css的代码,希望和大家交流下,有什么问题希望大家能不吝指教!

  • 相关阅读:
    Java字节流Stream的使用,创建方法
    Java中字节流和字符流复制文件
    Java中的IO流,Input和Output的用法,字节流和字符流的区别
    Java中String的常用方法总结
    java中File类的常用方法总结
    Java中递归的优缺点,Java写一个递归遍历目录下面的所有文件包括子文件夹里边的文件。
    Mysql 5.5从零开始学阅读笔记
    RDS for MySQL有哪些限制
    mysql查看建表语句命令
    MYSQL查看当前正在使用的数据库命令
  • 原文地址:https://www.cnblogs.com/zhaojia-dream/p/4788225.html
Copyright © 2011-2022 走看看