zoukankan      html  css  js  c++  java
  • (一)jQuery EasyUI 的EasyLoader载入原理

    1、第一次看了官网的demo。引用的是EasyLoader.js文件,而不是引用jquery.easyui.min.js文件,我就有疑问了,百度一下。

    jQuery EasyUI是一款基于JQueryUI高速搭建组件。

    EasyLoader是能够动态载入脚本和CSS文件。也能够动态载入EasyUI已有组件。须要引用EasyLoader.js文件,注意:这里就不须要引用jquery.easyui.min.js文件了。

    比方须要载入linkbutton组件。则能够用以下的两种方式来载入:

    第一种通过设置class来实现:

      <a href="#" class="easyui-linkbutton" onclick="load1()">载入日历</a>

       仅仅要class设置了easyui-组件名,easyloader就会自己主动动态载入对应的组件

    另外一种通过脚本来实现

      using('calendar'function () { alert("载入成功!

    ") });

       或者

      easyloader.load('calendar'function () { alert("载入成功。") });

       这里using 等同于 easyloader.load,也就是说using easyloader.load方法的简写。 

    经常使用属性:

    1)         Locale 本地化

    使用方法:easyloader.locale = "zh_CN"; // 本地化设置

    2)         Theme 主题

    使用方法:easyloader.theme = "gray"; // 设置主题

    事件:

    1)         onProgress 每一个组件载入完毕后触发

    2)         onLoad:在onProgress事件后触发,当组件以及关联组件所有载入完毕后触发

    两者的差别能够从名称中看出端倪。onProgress事件能够用来显示运行进度,而onLoad事件能够用于提示用户能够使用组件了。


    2、怎么动态载入js、css呢?

    事实上能够在http://www.zi-han.net/case/easyui/base.html     demo查看源代码就知道引用那些JS和CSS,而有些JS在demo中并没实用到怎么也会载入进来呢?好,先提示一点,每一个组件之间可能存在依赖。看老版本号的源代码就清楚 EasyLoader干了些什么

    /**
     * easyloader - jQuery EasyUI
     * 
     * Licensed under the GPL:
     *   http://www.gnu.org/licenses/gpl.txt
     *
     * Copyright 2010 stworthy [ stworthy@gmail.com ] 
     * 
     */
    (function(){
    	//将全部的插件。和插件资源和依赖文件放进modules对象中。
    	var modules = {
    		
    		draggable:{
    			js:'jquery.draggable.js'
    		},
    		droppable:{
    			js:'jquery.droppable.js'
    		},
    		resizable:{
    			js:'jquery.resizable.js'
    		},
    		linkbutton:{
    			js:'jquery.linkbutton.js',
    			css:'linkbutton.css'
    		},
    		pagination:{
    			js:'jquery.pagination.js',
    			css:'pagination.css',
    			dependencies:['linkbutton']
    		},
    		datagrid:{
    			js:'jquery.datagrid.js',
    			css:'datagrid.css',
    			dependencies:['panel','resizable','linkbutton','pagination']
    		},
    		treegrid:{
    			js:'jquery.treegrid.js',
    			css:'tree.css',
    			dependencies:['datagrid']
    		},
    		panel: {
    			js:'jquery.panel.js',
    			css:'panel.css'
    		},
    		window:{
    			js:'jquery.window.js',
    			css:'window.css',
    			dependencies:['resizable','draggable','panel']
    		},
    		dialog:{
    			js:'jquery.dialog.js',
    			css:'dialog.css',
    			dependencies:['linkbutton','window']
    		},
    		messager:{
    			js:'jquery.messager.js',
    			css:'messager.css',
    			dependencies:['linkbutton','window']
    		},
    		layout:{
    			js:'jquery.layout.js',
    			css:'layout.css',
    			dependencies:['resizable','panel']
    		},
    		form:{
    			js:'jquery.form.js'
    		},
    		menu:{
    			js:'jquery.menu.js',
    			css:'menu.css'
    		},
    		tabs:{
    			js:'jquery.tabs.js',
    			css:'tabs.css',
    			dependencies:['panel','linkbutton']
    		},
    		splitbutton:{
    			js:'jquery.splitbutton.js',
    			css:'splitbutton.css',
    			dependencies:['linkbutton','menu']
    		},
    		menubutton:{
    			js:'jquery.menubutton.js',
    			css:'menubutton.css',
    			dependencies:['linkbutton','menu']
    		},
    		accordion:{
    			js:'jquery.accordion.js',
    			css:'accordion.css',
    			dependencies:['panel']
    		},
    		calendar:{
    			js:'jquery.calendar.js',
    			css:'calendar.css'
    		},
    		combo:{
    			js:'jquery.combo.js',
    			css:'combo.css',
    			dependencies:['panel','validatebox']
    		},
    		combobox:{
    			js:'jquery.combobox.js',
    			css:'combobox.css',
    			dependencies:['combo']
    		},
    		combotree:{
    			js:'jquery.combotree.js',
    			dependencies:['combo','tree']
    		},
    		combogrid:{
    			js:'jquery.combogrid.js',
    			dependencies:['combo','datagrid']
    		},
    		validatebox:{
    			js:'jquery.validatebox.js',
    			css:'validatebox.css'
    		},
    		numberbox:{
    			js:'jquery.numberbox.js',
    			dependencies:['validatebox']
    		},
    		spinner:{
    			js:'jquery.spinner.js',
    			css:'spinner.css',
    			dependencies:['validatebox']
    		},
    		numberspinner:{
    			js:'jquery.numberspinner.js',
    			dependencies:['spinner','numberbox']
    		},
    		timespinner:{
    			js:'jquery.timespinner.js',
    			dependencies:['spinner']
    		},
    		tree:{
    			js:'jquery.tree.js',
    			css:'tree.css',
    			dependencies:['draggable','droppable']
    		},
    		datebox:{
    			js:'jquery.datebox.js',
    			css:'datebox.css',
    			dependencies:['calendar','validatebox']
    		},
    		parser:{
    			js:'jquery.parser.js'
    		}
    	};
    	//将国际化文件放入一个locales对象中
    	var locales = {
    		'af':'easyui-lang-af.js',
    		'bg':'easyui-lang-bg.js',
    		'ca':'easyui-lang-ca.js',
    		'cs':'easyui-lang-cs.js',
    		'da':'easyui-lang-da.js',
    		'de':'easyui-lang-de.js',
    		'en':'easyui-lang-en.js',
    		'fr':'easyui-lang-fr.js',
    		'nl':'easyui-lang-nl.js',
    		'zh_CN':'easyui-lang-zh_CN.js',
    		'zh_TW':'easyui-lang-zh_TW.js'
    	};
    	
    	//定义一个局部变量,做循环遍历时候。存放状态
    	var queues = {};
    	
    	//载入js方法
    	function loadJs(url, callback){
    		//标志变量,js是否载入并运行
    		var done = false;
    		var script = document.createElement('script');//创建script dom
    		script.type = 'text/javascript';
    		script.language = 'javascript';
    		script.src = url;
    		script.onload = script.onreadystatechange = function(){ //onload是firefox 浏览器事件,onreadystatechange,是ie的。为了兼容,两个都写上,这样写会导致内存泄露
    			//script.readyState仅仅是ie下有这个属性,假设这个值为undefined,说明是在firefox,就直接能够运行以下的代码了。反之为ie,须要对script.readyState
    			//状态详细值进行判别,loaded和complete状态表示,脚本载入了并运行了。
    			if (!done && (!script.readyState || script.readyState == 'loaded' || script.readyState == 'complete')){
    				done = true;
    				
    				script.onload = script.onreadystatechange = null;//释放内存,还会泄露。
    				if (callback){//载入后运行回调
    					callback.call(script);
    				}
    			}
    		}
    		//详细载入动作。上面的onload是注冊事件。
    		document.getElementsByTagName("head")[0].appendChild(script);
    	}
    	//运行js ,看代码逻辑可知,运行js,仅仅是在js运行后。将这个script删除而已,主要用来载入国际化文件
    	function runJs(url, callback){
    		loadJs(url, function(){
    			document.getElementsByTagName("head")[0].removeChild(this);
    			if (callback){
    				callback();
    			}
    		});
    	}
    	
    	//载入css没什么好说的
    	function loadCss(url, callback){
    		var link = document.createElement('link');
    		link.rel = 'stylesheet';
    		link.type = 'text/css';
    		link.media = 'screen';
    		link.href = url;
    		document.getElementsByTagName('head')[0].appendChild(link);
    		if (callback){
    			callback.call(link);
    		}
    	}
    	//载入单一一个plugin,细致研究module ,能够发现。pingin之间通过dependence,构造成了一颗依赖树。
    	//这种方法。就是载入详细树中的一个节点
    	function loadSingle(name, callback){
    		//把整个plugin的状态设置为loading
    		queues[name] = 'loading';
    		
    		var module = modules[name];
    		//把js状态设置为loading
    		var jsStatus = 'loading';
    		//假设同意css,而且plugin有css,则载入css,否则设置载入过了,事实上是不载入
    		var cssStatus = (easyloader.css && module['css']) ? 'loading' : 'loaded';
    		//载入css,plugin 的css,假设是全称,就用全称。否则把简写换成全称。所以简写的css文件要放入到themes/type./文件下
    		if (easyloader.css && module['css']){
    			if (/^http/i.test(module['css'])){
    				var url = module['css'];
    			} else {
    				var url = easyloader.base + 'themes/' + easyloader.theme + '/' + module['css'];
    			}
    			loadCss(url, function(){
    				cssStatus = 'loaded';
    				//js, css载入完,才调用回调
    				if (jsStatus == 'loaded' && cssStatus == 'loaded'){
    					finish();
    				}
    			});
    		}
    		//载入js,全称用全称,简写补全。

    if (/^http/i.test(module['js'])){ var url = module['js']; } else { var url = easyloader.base + 'plugins/' + module['js']; } loadJs(url, function(){ jsStatus = 'loaded'; if (jsStatus == 'loaded' && cssStatus == 'loaded'){ finish(); } }); //载入完调用的方法。改plugin状态 function finish(){ queues[name] = 'loaded'; //调用正在载入的方法,事实上已经载入完了, easyloader.onProgress(name); if (callback){ callback(); } } } //载入主模块入口。 function loadModule(name, callback){ //定义数组,最后是形成的是依赖插件列表,最独立的插件放在首位,name是末尾 var mm = []; var doLoad = false; //name有两种。一种是string ,一种是string array,这样一次能够载入多个plugin,都是调用add方法进行加入 if (typeof name == 'string'){ add(name); } else { for(var i=0; i<name.length; i++){ add(name[i]); } } function add(name){ //假设modules中没有这个plugin那退出 if (!modules[name]) return; //假设有。查看它是否依赖其它plugin var d = modules[name]['dependencies']; //假设依赖,就载入依赖的plugin.同一时候在载入依赖的plugin的依赖。注意循环中调用了add,是递归 if (d){ for(var i=0; i<d.length; i++){ add(d[i]); } } mm.push(name); } function finish(){ if (callback){ callback(); } //调用onLoad,传递name 为參数 easyloader.onLoad(name); } //形成依赖树,不行还没有做实质性工作呢,那就是载入。

    打起精神来。最核心的代码就是以下的了 //超时用 var time = 0; //定义一个载入方法。定义后直接调用 function loadMm(){ //假设mm有长度,长度!=0,载入plugin,为0,即载入完毕。開始载入国际化文件。 if (mm.length){ var m = mm[0]; // the first module if (!queues[m]){//状态序列中没有这个plugin的信息,说明没有载入这个plug,调用laodSingle进行载入 doLoad = true; loadSingle(m, function(){ mm.shift();//载入完毕后,将这个元素从数组去除,在继续载入,直到数组 loadMm(); }); } else if (queues[m] == 'loaded'){//假设这个plugin已经载入,就不用载入,以为mm中可能有反复项 mm.shift(); loadMm(); } else { if (time < easyloader.timeout){//超时时候。10秒钟调用一次loadMn().注意arguments.callee代表函数本身 time += 10; setTimeout(arguments.callee, 10); } } } else { if (easyloader.locale && doLoad == true && locales[easyloader.locale]){ var url = easyloader.base + 'locale/' + locales[easyloader.locale]; runJs(url, function(){ finish(); }); } else { finish(); } } } loadMm(); } // 定义一个载入器,注意,是全局变量。没有var, easyloader = { modules:modules, locales:locales, base:'.',//该属性是为了载入js,记录目录路径的 theme:'default', //默认主题 css:true, locale:null, timeout:2000,//载入超时事件 //easyloader.load(),该模块载入的调用方法,先载入css,然后载入js load: function(name, callback){ //假设载入是*.css文件,推断是不是以http开头,假设是,直接调用 if (/.css$/i.test(name)){ if (/^http/i.test(name)){ loadCss(name, callback); } else { //不是http的。加上base.目录路径 loadCss(easyloader.base + name, callback); } } //载入js文件 else if (/.js$/i.test(name)){ if (/^http/i.test(name)){ loadJs(name, callback); } else { loadJs(easyloader.base + name, callback); } } else { //假设直接传递一个插件名,就去modole数组中载入。改方法是重点,也是easyui自带的plugin载入方式 loadModule(name, callback); } }, onProgress: function(name){}, onLoad: function(name){} }; //以上一直在定义函数,和变量。此处为真正运行处 //获取页面的全部的script,主要是为了获取我们如今解释的easyloader.js文件路径,来设置base属性 var scripts = document.getElementsByTagName('script'); for(var i=0; i<scripts.length; i++){ var src = scripts[i].src; if (!src) continue; var m = src.match(/easyloader.js(W|$)/i);//推断文件是否含有easyloadr.js if (m){ //假设有。base为easyloadr.js 的同样前缀 easyloader.base = src.substring(0, m.index); } } //定义一个简化调用接口 window.using = easyloader.load; if (window.jQuery){ jQuery(function(){ //系统数据载入完后,载入parser.js插件,该插件是渲染界面的 easyloader.load('parser', function(){ jQuery.parser.parse();//渲染方法 }); }); } })();




     
  • 相关阅读:
    【NOIP 2003】 加分二叉树
    【POJ 1655】 Balancing Act
    【HDU 3613】Best Reward
    【POJ 3461】 Oulipo
    【POJ 2752】 Seek the Name, Seek the Fame
    【POJ 1961】 Period
    【POJ 2406】 Power Strings
    BZOJ3028 食物(生成函数)
    BZOJ5372 PKUSC2018神仙的游戏(NTT)
    BZOJ4836 二元运算(分治FFT)
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/6751858.html
Copyright © 2011-2022 走看看