EasyUI学习笔记(四)——学习读源码--easyloader源码阅读分析
来源:互联网 发布:生意通软件手机版 编辑:程序博客网 时间:2024/05/21 11:34
easyloader :
在上篇笔记中简单概括下:
easyloader作用:
easyloader模块是用来加载jquery easyui的js和css文件的,而且可以分析模块的依赖关系,先加载依赖项。模块加载好了会调用parse模块来解析页面。把class是easyui开头的标签都转化成easyui的控件。
分析源代码:
具体的分析笔记都已写在注释中:
/** * jQuery EasyUI 1.5 * * Copyright (c) 2009-2016 www.jeasyui.com. All rights reserved. * * Licensed under the freeware license: * http://www.jeasyui.com/license_freeware.php To use it on other terms please * contact us: info@jeasyui.com * */(function() { // modules : _1,(见第380行),将所有的插件、插件资源和依赖文件放进modules对象中 var _1 = { draggable : { // 可拖拽 js : "jquery.draggable.js" }, droppable : { // 可释放 js : "jquery.droppable.js" }, resizable : { // 可调整尺寸 js : "jquery.resizable.js" }, linkbutton : { // 链接按钮 js : "jquery.linkbutton.js", css : "linkbutton.css" }, progressbar : { // 进度条 js : "jquery.progressbar.js", css : "progressbar.css" }, tooltip : { // 工具提示框 js : "jquery.tooltip.js", css : "tooltip.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" ] }, propertygrid : { // 属性表格 js : "jquery.propertygrid.js", css : "propertygrid.css", dependencies : [ "datagrid" ] }, datalist : { // 数据列表 js : "jquery.datalist.js", css : "datalist.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", "dialog", "progressbar" ] }, 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" ] }, menubutton : { // 菜单按钮 js : "jquery.menubutton.js", css : "menubutton.css", dependencies : [ "linkbutton", "menu" ] }, splitbutton : { // 拆分按钮 js : "jquery.splitbutton.js", css : "splitbutton.css", dependencies : [ "menubutton" ] }, switchbutton : { // 开关按钮 js : "jquery.switchbutton.js", css : "switchbutton.css" }, accordion : { // 手风琴 js : "jquery.accordion.js", css : "accordion.css", dependencies : [ "panel" ] }, calendar : { // 日历 js : "jquery.calendar.js", css : "calendar.css" }, textbox : { // 文本框 js : "jquery.textbox.js", css : "textbox.css", dependencies : [ "validatebox", "linkbutton" ] }, passwordbox : { // 密码输入框 js : "jquery.passwordbox.js", css : "passwordbox.css", dependencies : [ "textbox" ] }, filebox : { // 文件框 js : "jquery.filebox.js", css : "filebox.css", dependencies : [ "textbox" ] }, combo : { // 组合 js : "jquery.combo.js", css : "combo.css", dependencies : [ "panel", "textbox" ] }, 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" ] }, combotreegrid : { // 下拉表格树 js : "jquery.combotreegrid.js", dependencies : [ "combo", "treegrid" ] }, validatebox : { // 验证框 js : "jquery.validatebox.js", css : "validatebox.css", dependencies : [ "tooltip" ] }, numberbox : { // 数字框 js : "jquery.numberbox.js", dependencies : [ "textbox" ] }, searchbox : { // 搜索框 js : "jquery.searchbox.js", css : "searchbox.css", dependencies : [ "menubutton", "textbox" ] }, spinner : { // 微调器 js : "jquery.spinner.js", css : "spinner.css", dependencies : [ "textbox" ] }, 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", "combo" ] }, datetimebox : { // 日期时间框 js : "jquery.datetimebox.js", dependencies : [ "datebox", "timespinner" ] }, slider : { // 滑块 js : "jquery.slider.js", dependencies : [ "draggable" ] }, parser : { // 解析器 js : "jquery.parser.js" }, mobile : { js : "jquery.mobile.js" } }; // 将国际化文件放入一个locales对象中 var _2 = { "af" : "easyui-lang-af.js", "ar" : "easyui-lang-ar.js", "bg" : "easyui-lang-bg.js", "ca" : "easyui-lang-ca.js", "cs" : "easyui-lang-cs.js", "cz" : "easyui-lang-cz.js", "da" : "easyui-lang-da.js", "de" : "easyui-lang-de.js", "el" : "easyui-lang-el.js", "en" : "easyui-lang-en.js", "es" : "easyui-lang-es.js", "fr" : "easyui-lang-fr.js", "it" : "easyui-lang-it.js", "jp" : "easyui-lang-jp.js", "nl" : "easyui-lang-nl.js", "pl" : "easyui-lang-pl.js", "pt_BR" : "easyui-lang-pt_BR.js", "ru" : "easyui-lang-ru.js", "sv_SE" : "easyui-lang-sv_SE.js", "tr" : "easyui-lang-tr.js", "zh_CN" : "easyui-lang-zh_CN.js", "zh_TW" : "easyui-lang-zh_TW.js" }; // _3=queues,加载队列,定义一个局部变量,做循环遍历时候,存放状态 var _3 = {}; // _4=loadJs,_5=url _6=callback ,加载js文件函数,过程就是动态创建一个script标签,然后添加到head标签中去 function _4(_5, _6) { // _7=done,标志变量,js是否加载并执行 var _7 = false; // _8=script,创建script dom var _8 = document.createElement("script"); _8.type = "text/javascript"; _8.language = "javascript"; _8.src = _5; // _5=url /* * 监听了script标签的两个事件函数,一个是onload,另一个是onreadystatechange,这个主要是针对IE和非IE浏览器准备的。 * onload是firefox 浏览器事件,onreadystatechange是ie的,为了兼容,两个都写上,这样写会导致内存泄露 */ _8.onload = _8.onreadystatechange = function() { /* * script.readyState只是ie下有这个属性: * 如果这个值为undefined,说明是在firefox,就直接可以执行下面的代码了; * 反之为ie,需要对script.readyState状态具体值进行判别: * loaded和complete状态表示,脚本加载了并执行了 */ if (!_7 && (!_8.readyState || _8.readyState == "loaded" || _8.readyState == "complete")) { _7 = true; // 释放内存,还会泄露 _8.onload = _8.onreadystatechange = null; // 加载后执行回调 if (_6) { _6.call(_8); } } }; // 具体的加载动作,上面的onload是注册事件 document.getElementsByTagName("head")[0].appendChild(_8); } ; /** * _9=runJs,运行js文件。就是把js文件加载进来,在js执行之后将这个script再remove删除掉 ,主要用来加载国际化文件 * @param url js的url * @callback 回调函数,执行完js时会调用这个函数 */ function _9(_a, _b) { _4(_a, function() { document.getElementsByTagName("head")[0].removeChild(this); if (_b) { _b(); } }); } ; /** * 加载css文件。和加载js文件一样,动态创建一个link标签,然后追加到head标签中去 * @param url css的url * @param callback 回调函数,加载完成后调用此函数 */ function _c(_d, _e) { var _f = document.createElement("link"); _f.rel = "stylesheet"; _f.type = "text/css"; _f.media = "screen"; _f.href = _d; document.getElementsByTagName("head")[0].appendChild(_f); if (_e) { _e.call(_f); } } ; /** * _10=loadSingle(name,callback),加载单独的一个plugin * 分析module可以发现plugin之间通过dependence依赖构造了一棵依赖树 */ function _10(_11, _12) { // 加载具体树中的一个节点 // queues[name] , 加载队列存入该plugin名,并把整个plugin的状态设置为loading _3[_11] = "loading"; // var module = modules[name];根据模块名,取出该模块定义 var _13 = _1[_11]; // jsStatus,js的加载状态,把js状态设置为loading var _14 = "loading"; // _15=cssStatus,css加载状态,从这里可以看出easyloader.css就是一个开关变量,控制是否加载模块相应的css文件 //_13=module 如果允许css,并且plugin有css,则加载css,否则设置加载过了,其实就是不加载 var _15 = (easyloader.css && _13["css"]) ? "loading" : "loaded"; // 是css文件,加载css,plugin 的css,如果是全称,就用全称,否则把简写换成全称,所以简写的css文件要放入到themes/type./文件下 if (easyloader.css && _13["css"]) { if (/^http/i.test(_13["css"])) { var url = _13["css"]; } else { var url = easyloader.base + "themes/" + easyloader.theme + "/" + _13["css"]; } _c(url, function() { _15 = "loaded"; // js, css都加载完,才调用回调 if (_14 == "loaded" && _15 == "loaded") { _16(); // _16=finish } }); } // 如果是js文件,就用LoadJs来加载js,全称用全称,简写补全 if (/^http/i.test(_13["js"])) { var url = _13["js"]; } else { var url = easyloader.base + "plugins/" + _13["js"]; } _4(url, function() { _14 = "loaded"; if (_14 == "loaded" && _15 == "loaded") { _16(); } }); /** * _16()=finish()函数,来结束加载。 * 加载完调用的方法,并触发onProgress函数,每加载成功一个模块,就调用一次onProgress,改变plugin状态 */ function _16() { _3[_11] = "loaded"; // 调用正在加载的方法,其实已经加载完了 easyloader.onProgress(_11); if (_12) { _12(); } } ; } ; /** * loadModule(name, callback),easyui模块加载函数 * @param name 模块名,可以是string,也可以是数组 * @param callback 回调函数,当加载结束后会调用此函数 */ function _17(_18, _19) { // 模块名数组,根据依赖关系,从前到后,依次排开,最后是形成的是依赖插件列表,最独立的插件放在首位,name是末尾 var mm = []; //_1a=doLoad,加载标识,当其值为true时,表示需要加载的模块已经加载好了 var _1a = false; //模块名name支持两种,一种是string ,一种是string array,这样一次可以加载多个plugin,都是调用add方法进行添加 if (typeof _18 == "string") { // 是string的时候,调用add方法把模块名push到mm数组中去 add(_18); } else { for (var i = 0; i < _18.length; i++) { // 是数组的时候,循环调用add()方法把模块名统统push到mm数组中去 add(_18[i]); } } /** * loadModule函数中内嵌的一个函数,用来加载模块名到变量mm数组中去 * @param name 模块名,只能是string */ function add(_1b) { // 相当于一个保护措施,如果在modules中该模块名不存在,也就是说没有这个plugin不存在,我们就不要加载了直接退出 if (!_1[_1b]) { return; } //如果modules有这个plugin,就去查看它是否依赖其他plugin var d = _1[_1b]["dependencies"]; //如果它依赖了其它plugin,就加载依赖的plugin。同时再加载依赖的plugin的依赖。 if (d) { for (var i = 0; i < d.length; i++) { add(d[i]); //在循环中调用了add() 也就是是递归 } } mm.push(_1b);// 把模块名放到mm中 } ; /** * 当一个模块plugin及其依赖模块加载完成时,执行回调函数,并且触发onLoad函数 */ function _1c() { if (_19) { _19(); } //调用onLoad,传递name 为参数 easyloader.onLoad(_18); } ;//形成依赖树,下面就是做实质性工作——加载 //_1d = time ,加载用时 var _1d = 0; /** * _1e() = loadMm(),定义一个加载方法,加载所需要的模块,定义后直接调用 * 需要的模块,我们已经统计好了,并按依赖关系,先后push到mm中去了 */ function _1e() { //如果mm有长度,长度!=0,加载plugin,为0,即加载完毕,开始加载国际化文件 if (mm.length) { // 判断mm是不是空的 var m = mm[0]; //第一个module // 加载队列不包含此模块,状态序列中没有这个plugin的信息,说明没有加载这个plug,调用laodSingle进行加载 if (!_3[m]) { _1a = true; // 把doLoad置成true,表示开始加载 // 调用loadSingle方法来加载模块,加载成功后会把此模块从mm中shift掉,然后继续调用loadMM方法,就形成了递归调用 _10(m, function() { mm.shift();//加载完成后,将这个元素从数组去除,在继续加载,直到数组内的元素都加载完 _1e(); }); } else { //加载队列已经加载过此模块了,不需要在加载了,直接从mm中shift掉即可 if (_3[m] == "loaded") { mm.shift(); _1e(); } else { // 正在加载该模块,累计所用时间如果没有超过timeout 超过10毫秒再调用一次loadMm函数 if (_1d < easyloader.timeout) {//若是超时了,10秒钟调用一次loadMn() _1d += 10; setTimeout(arguments.callee, 10);//arguments.callee代表函数本身 } } } } else { // 走到这里,表示该加载的模块都已经加载好了 if (easyloader.locale && _1a == true && _2[easyloader.locale]) { // 如果设置了国际化,并且已经加载好了,而且该国际化资源还存在,那么加载该资源js var url = easyloader.base + "locale/"+ _2[easyloader.locale]; // runJs执行js完事后,调用finish方法 _9(url, function() { _1c(); }); } else {// 没定义国际化文件,就直接调用finish方法 _1c(); } } } ; _1e(); } ; /** * 定义一个加载器 * easyloader定义为全局变量 没有var */ easyloader = { // 各个模块文件的定义,包括js、css和依赖模块 modules : _1, // 国际化资源文件 locales : _2, // jquery-easyui的根目录,该属性是为了加载js,记录文件夹路径的,在加载easyloader时,会自动根据放置的位置而改变 base : ".", // 控件的主题 theme : "default", //默认主题 // 一个开关变量,控制easyloader加载模块时,要不要加载相应的css文件 css : true,//默认是需要加载的 /*国际化语言,可以根据window.navigator.language或者window.navigator.userLanguage来获取当前浏览器的语言。 有两个属性,主要因为IE浏览器只认识userLanguage和sysLanguage*/ locale : null, // 加载超时事件,加载一个模块的最长时间,超过这个时间,就开始加载下一个模块了 timeout : 2000, /** * easyloader.load(name, callback),该模块加载的调用方法,先加载css,然后加载js * name是模块名,callback是加载成功后执行的函数 */ load : function(_1f, _20) { if (/\.css$/i.test(_1f)) {// 如果模块名是以.css结尾 if (/^http/i.test(_1f)) { // 如果模块名是以http开头,那么css是一个文件的url _c(_1f, _20); } else { //不是http的,说明模块名相对于jquery easyui根目录来说的,加上base.文件夹路径 _c(easyloader.base + _1f, _20); } } //加载js文件 else { if (/\.js$/i.test(_1f)) {// 如果模块名是以.js结尾 if (/^http/i.test(_1f)) {// 如果模块名是以http开头,那么js是一个文件的url _4(_1f, _20); } else {// 否则,说明模块名相对于jquery easyui根目录来说的 _4(easyloader.base + _1f, _20); } } else { //以上两种都不是,直接传递一个插件名,说明是easyui自己的模块,就去modole数组中直接使用loadModule来加载。该方法是重点,也是easyui自带的plugin加载方式 _17(_1f, _20); } } }, // 当一个模块加载完会触发此函数 onProgress : function(_21) { }, // 当一个模块和其依赖都加载完会触发此函数 onLoad : function(_22) { } }; // // /** * 以上一直在定义函数、变量,此处是真正开始执行处 * _23=scripts 获取页面的所有的script,主要是为了获取现在解释的easyloader.js文件路径,来设置base属性 * 就是查找jquery-easyui的根目录,并赋值给easyloader的base属性上 这样easyloader再加载css文件和js文件就很方便定位了。 */ var _23 = document.getElementsByTagName("script"); for (var i = 0; i < _23.length; i++) { var src = _23[i].src; if (!src) { continue; } var m = src.match(/easyloader\.js(\W|$)/i); //判断文件是否含有easyloader.js if (m) { //如果有,base就是easyuiloader.js的相同前缀 easyloader.base = src.substring(0, m.index); } } /** * 定义一个简化调用接口 * 这个就起一个别名的作用,比如页面中可以想如下这么下: * using('window'); * 这样window模块就加载进来了! */ window.using = easyloader.load; /** * easyloader.js加载的第一个模块是parse模块, * parser模块调用parse方法,可以解析页面上的easyui控件 */ if (window.jQuery) { jQuery(function() { //系统数据加载完后,加载parser.js插件,该插件是渲染界面的 easyloader.load("parser", function() { jQuery.parser.parse();//渲染方法 }); }); }})();
- 属性:
- 事件
- 使用示例:
<%@ page language="java" pageEncoding="UTF-8"%><!DOCTYPE html><head> <title>EasyUI学习笔记————EasyUI的easyLoader源码分析</title> <!-- 引入jQuery 核心库--> <script type="text/javascript" src="${pageContext.request.contextPath}/jquery-easyui-1.5/jquery.min.js"></script> <!-- 引入easyLoader.js --> <script type="text/javascript" src="${pageContext.request.contextPath}/jquery-easyui-1.5/easyloader.js"></script> <script> function load1(){ using('calendar', function(){ $('#cc').calendar({ width:180, height:180 }); }); } function load2(){ using(['dialog','messager'], function(){ $('#dd').dialog({ title:'Dialog', width:300, height:200 }); $.messager.show({ title:'info', msg:'dialog created' }); }); } </script></head><body> <h1>EasyLoader Test</h1> <a href="#" class="easyui-linkbutton" onclick="load1()">Load Calendar</a> <a href="#" class="easyui-linkbutton" onclick="load2()">Load Dialog</a> <div id="cc"></div> <div id="dd"></div></html>
运行效果:
最近在学习前端的有关技术,也思考一个问题:
之前自己用过的东西,再次使用的时候,为什么效率还是那么低,相比较第一次没有进步。分析原因,就是太依赖于搜索引擎,实现什么样的效果或功能,自己写一点遇到问题直接上网搜一下,从来不会看框架源码也不看demo文档。一搜问题轻松解决了,好像是自己能会使用这个东西了,而且相比较一行行地读源码分析解决问题快多了。但下次遇到相同的东西,还是继续上网搜。小的项目这样看不出什么,如果真要做开发工作,这样的效率很低,因为没有形成自己逻辑思维,也没有自己思考总结,不管用多少次,都没有自己地东西。个人觉得,如果可以的话,尝试自己读一读源码,一是可以熟悉自己所使用框架或技术的基本原理,二对自己的思维逻辑提升也有好处,毕竟好的框架能够被广泛使用势必有其它框架不能比的优势。搜索再强大也比不上从自己脑子里读取快。
0 0
- EasyUI学习笔记(四)——学习读源码--easyloader源码阅读分析
- EasyUI学习总结(三)——easyloader源码分析
- EasyUI学习总结(三)——easyloader源码分析(转载)
- EasyUI学习总结(三)——easyloader源码分析
- EasyUI学习总结(三)——easyloader源码分析
- Ui学习笔记---EasyUI的EasyLoader组件源码分析
- EasyUI学习笔记(五)——学习读源码--parser源码阅读分析1
- EasyUI学习笔记(六)——学习读源码--parser源码阅读分析2
- EasyUI学习总结(四)——parser源码分析
- EasyUI学习总结(四)——parser源码分析
- EasyUI学习总结(四)——parser源码分析
- EasyUI学习总结(四)——parser源码分析
- EasyUI学习总结(二)——easyloader分析与使用
- EasyUI学习总结(二)——easyloader分析与使用
- EasyUI学习总结(二)——easyloader分析与使用
- EasyUI学习笔记(三)——学习使用EasyUI之easyloader 加载
- EasyUI学习总结(二)——easyloader分析与使用(转载)
- easyui 源码分析(easyloader.js)(2)
- Linux内核补丁升级
- tomcat7.0.55配置单向和双向HTTPS连接 (一)
- 机器学习性能改善备忘单:32个帮你做出更好预测模型的技巧和窍门
- IP地址的分类及其分类方法介绍
- 最大似然估计的一些优点
- EasyUI学习笔记(四)——学习读源码--easyloader源码阅读分析
- 更新补丁Bind
- 【POJ 2686 Traveling by Stagecoach】+ 状压dp
- Eclipse4.2安装FlashBuilder插件
- json教程---JavaScript的eval函数转换json对象
- android之adb shell
- tomcat7.0.55配置单向和双向HTTPS连接(二)
- POJ 3468 - A Simple Problem with Integers(线段树区间更新)
- Linux中OpenCV安装及在Intellij Idea中Java调用