Extjs 模块化动态加载js实践

http://yiminghe.iteye.com/blog/313699

前一段转载了一篇

透明加载外部 javascript 文件函数

挺有启发的,觉得可以套用在extjs的管理上,管理界面 两栏布局,左边栏一棵菜单树,右面一个tabpanel,菜单树的每个菜单代表一个模块,每个模块用一个js来实现,需要时载入就行了,而不需要刚开始时把所有的模块都载进入


当点击菜单树的节点时调用:

 

Js代码 复制代码 收藏代码
  1. function openGetBugsPanel(name) {   
  2.     var moduleId = 'BugList_tab';   
  3.     //一个静态方法,表示从一个js载入了一个新的模块   
  4.     Ext.ux.yiminghe.framework.core.newModule(   
  5.     {   
  6.         //模块的id        
  7.         moduleId: moduleId,   
  8.         //在哪个tabpanel新加一个模块    
  9.         tabPanel: window.tabs,   
  10.         //模块所在js   
  11.         moduleURL: 'js/modules/Bugs.js',   
  12.         //模块所需要的参数   
  13.         moduleParams: {   
  14.             title: name,   
  15.             MYBugs: false  
  16.         },   
  17.         //如果该模块已经在tabpanel上了,怎么处理              
  18.         existCallBack: function(panel) {   
  19.             panel.setTitle(name);   
  20.             panel.filters.clearFilters();   
  21.         }   
  22.     }   
  23.     );   
  24. }  
 

 

其实每个模块就是一个panel,加入到tabpanel 就行了,关键是要 动态构造这个panel

例如这个bugs.js

 

Js代码 复制代码 收藏代码
  1. /**  
  2.     ajax 直接返回一个类,eval ,new  
  3. **/  
  4. Ext.extend(Ext.Panel, {   
  5.     initComponent: function() {   
  6.   
  7.         var bugsGrid_metaData = [   
  8.         {   
  9.             dataIndex: 'projectId',   
  10.             header: '项目',   
  11.             width: 70,   
  12.             sortable: true,   
  13.             show: true  
  14.         },   
  15.         {   
  16.             dataIndex: 'moduleId',   
  17.             header: '模块',   
  18.             width: 70,   
  19.             sortable: true,   
  20.             show: true  
  21.         },   
  22.         {   
  23.             dataIndex: 'bid',   
  24.             header: 'Bug/Task编号',   
  25.             sortable: true,   
  26.             width: 100   
  27.         },   
  28.         {   
  29.             dataIndex: 'btitle',   
  30.             header: 'Bug/Task标题',   
  31.             width: 250,   
  32.             sortable: true,   
  33.             show: true  
  34.   
  35.         },   
  36.         {   
  37.             dataIndex: 'degree',   
  38.             header: '严重程度',   
  39.             width: 100,   
  40.             sortable: true,   
  41.             show: true,   
  42.             renderer: function(val) {   
  43.                 return '<span style="color:green">' + val + '</span> ';   
  44.             }   
  45.         },   
  46.         {   
  47.             dataIndex: 'status',   
  48.             header: '状态',   
  49.             width: 70,   
  50.             show: true,   
  51.             sortable: true,   
  52.             renderer: function(val) {   
  53.   
  54.   
  55.                 return '<span style="color:red">' + val + '</span> ';   
  56.             }   
  57.         },   
  58.         {   
  59.             dataIndex: 'who',   
  60.             header: '由谁创建',   
  61.             width: 70,   
  62.             sortable: true,   
  63.             show: true  
  64.         },   
  65.         {   
  66.             dataIndex: 'assign',   
  67.             header: '指派给谁',   
  68.             width: 70,   
  69.             sortable: true,   
  70.             show: true  
  71.         },   
  72.         {   
  73.             dataIndex: 'resolve',   
  74.             header: '由谁解决',   
  75.             width: 70,   
  76.             sortable: true,   
  77.             show: true  
  78.         },   
  79.         {   
  80.             dataIndex: 'moduleId',   
  81.             header: 'moduleId',   
  82.             sortable: true,   
  83.             width: 70   
  84.         },   
  85.         {   
  86.             dataIndex: 'method',   
  87.             header: '解决方案',   
  88.             width: 100,   
  89.             sortable: true,   
  90.             show: true  
  91.         },   
  92.         {   
  93.             dataIndex: 'openedTime',   
  94.             header: '提交时间',   
  95.             width: 150,   
  96.             sortable: true,   
  97.             show: true,   
  98.             renderer: function(val) {   
  99.   
  100.                 var d = new Date();   
  101.                 d.setTime(val);   
  102.                 return '<span style="color:red">' + d.toLocaleString() + '</span> ';   
  103.             }   
  104.         }   
  105.         ];   
  106.   
  107.         Ext.grid.filter.StringFilter.prototype.icon = 'desktop/js/filter/img/find.png';   
  108.         this.filters = new Ext.grid.GridFilters({   
  109.             filters: [   
  110.             {   
  111.                 type: 'list',   
  112.                 dataIndex: 'projectId',   
  113.                 single: true,   
  114.                 options: PROJECTS,   
  115.                 phpMode: true,   
  116.                 listeners: {   
  117.                     'update'function() {   
  118.                         var pid = this.getValue();   
  119.                         if (pid == ''return;   
  120.                         // 实例化Ext发送Ajax请求需要的Connection对象   
  121.                         var conn = new Ext.data.Connection();   
  122.                         // 发送异步请求   
  123.                         conn.request({   
  124.                             // 请求地址   
  125.                             url: 'bug/get_modules_ext.jsp?project_id=' + pid,   
  126.                             method: 'GET',   
  127.                             // 指定回调函数   
  128.                             callback: callback   
  129.                         });   
  130.                         //回调函数   
  131.                         function callback(options, success, response) {   
  132.                             if (success) {   
  133.                                 // 如果成功则使用Ext将JSON字符串转换为JavaScript对象   
  134.                                 var jsonObj = Ext.util.JSON.decode(response.responseText);   
  135.                                 // 到这就可以取你想要的东东了   
  136.                                 //  取消息id   
  137.                                 var m_data = jsonObj.data;   
  138.                                 filters.getFilter(1).options = m_data;   
  139.                                 filters.getFilter(1).store.loadData(m_data);   
  140.                             } else {   
  141.                                 alert(response.responseText);   
  142.                             }   
  143.   
  144.                         }   
  145.                     }   
  146.                 }   
  147.             },   
  148.             {   
  149.                 type: 'list',   
  150.                 dataIndex: 'moduleId',   
  151.                 single: true,   
  152.                 options: [],   
  153.                 phpMode: true  
  154.             },   
  155.             {   
  156.                 type: 'string',   
  157.                 dataIndex: 'btitle'  
  158.             },   
  159.   
  160.             {   
  161.                 type: 'list',   
  162.                 dataIndex: 'assign',   
  163.                 single: true,   
  164.                 //id:'assign_filter',   
  165.                 options: USERS,   
  166.                 phpMode: true  
  167.             },   
  168.             {   
  169.                 type: 'list',   
  170.                 dataIndex: 'who',   
  171.                 single: true,   
  172.                 options: USERS,   
  173.                 phpMode: true  
  174.             },   
  175.   
  176.             {   
  177.                 type: 'list',   
  178.                 dataIndex: 'resolve',   
  179.                 single: true,   
  180.                 options: USERS,   
  181.                 phpMode: true  
  182.             },   
  183.             {   
  184.                 type: 'list',   
  185.                 dataIndex: 'status',   
  186.                 single: true,   
  187.                 //id:'status_filter',   
  188.                 options: BUGSTATUSES,   
  189.                 phpMode: true  
  190.             }   
  191.             ]   
  192.         });   
  193.   
  194.         var gridMenuDatas = [   
  195.         {   
  196.             text: '提交Bug/Task',   
  197.             iconCls: 'badd',   
  198.             handler: function() {   
  199.                 addBugFormPanel('提交Bug/Task');   
  200.             }   
  201.         },   
  202.         '-',   
  203.         {   
  204.             text: '编辑',   
  205.             iconCls: 'bedit',   
  206.             handler: function() {   
  207.                 var record = this.getSelectionRecord();   
  208.                 createEditBugForm(record.get('bid'), record.get('btitle'));   
  209.             }   
  210.         }   
  211.         ,   
  212.         '-',   
  213.         {   
  214.             text: '解决',   
  215.             iconCls   
  216.             :   
  217.             'bok',   
  218.             handler   
  219.             :   
  220.             function() {   
  221.                 var record = this.getSelectionRecord();   
  222.                 createResolveBugForm(record.get('bid'), record.get('btitle'), record.get('moduleId'));   
  223.             }   
  224.         }   
  225.         ,   
  226.         '-',   
  227.         {   
  228.             text: '历史',   
  229.             iconCls: 'bsearch',   
  230.             handler: function() {   
  231.                 var record = this.getSelectionRecord();   
  232.                 var moduleId = 'bugHistory_Tab' + record.get('bid');   
  233.                 var realId = 'bugHistory_Tab' + record.get('bid');   
  234.                 Ext.ux.yiminghe.framework.core.newModule(   
  235.                 {   
  236.                     moduleId: moduleId,   
  237.                     realId: realId,   
  238.                     tabPanel: window.tabs,   
  239.                     moduleURL: 'js/modules/BugHistories.js',   
  240.                     moduleParams: {   
  241.                         bugId: record.get('bid'),   
  242.                         bugName: record.get('btitle'),   
  243.                         moduleId: record.get('moduleId')   
  244.                     },   
  245.                     existCallBack: function(panel) {   
  246.                         panel.bugHistoryGrid.reload();   
  247.                     }   
  248.                 }   
  249.                 );   
  250.             }   
  251.         },   
  252.         {   
  253.             text: '链接地址',   
  254.             iconCls: 'blist',   
  255.             handler: function() {   
  256.                 var record = this.getSelectionRecord();   
  257.                 if (record)   
  258.                 Ext.MessageBox.alert(record.get('btitle') + ' - Bug地址', BASEPATH + '/bug/BtsBugDetail.jsp?bugId=' + record.get('bid'));   
  259.             }   
  260.         }   
  261.   
  262.         ];   
  263.         var gridContextMenuDatas = [   
  264.         gridMenuDatas[0], gridMenuDatas[2], gridMenuDatas[4], gridMenuDatas[6], gridMenuDatas[7]   
  265.         ];   
  266.         var dbClick_g = function(record) {   
  267.             var moduleId = 'bugHistory_Tab';   
  268.             var realId = 'bugHistory_Tab' + record.get('bid');   
  269.             Ext.ux.yiminghe.framework.core.newModule(   
  270.             {   
  271.                 moduleId: moduleId,   
  272.                 realId: realId,   
  273.                 tabPanel: window.tabs,   
  274.                 moduleURL: 'js/modules/BugHistories.js',   
  275.                 moduleParams: {   
  276.                     bugId: record.get('bid'),   
  277.                     bugName: record.get('btitle'),   
  278.                     moduleId: record.get('moduleId')   
  279.                 },   
  280.                 existCallBack: function(panel) {   
  281.                     panel.bugHistoryGrid.reload();   
  282.                 }   
  283.             }   
  284.             );   
  285.         };   
  286.         this.bugsGrid = new Ext.ux.yiminghe.JsonGridPanel({   
  287.             columns: bugsGrid_metaData,   
  288.             pageSize: 15,   
  289.             initload: true,   
  290.             plugins: [this.filters],   
  291.             viewConfig: {   
  292.                 forceFit: true,   
  293.                 autoFill: true  
  294.             },   
  295.             autoScroll: true,   
  296.             sm: new Ext.grid.RowSelectionModel(   
  297.             {   
  298.                 singleSelect: true  
  299.             }),   
  300.             dataSource: 'bug/BtsGetBugsDO_Ext.jsp',   
  301.             tbar: gridMenuDatas,   
  302.             stripeRows: true,   
  303.             border: false,   
  304.             bodyStyle: 'width:100%',   
  305.             isGroupHeader: false,   
  306.             rowcontextmenu: gridContextMenuDatas,   
  307.             doubleClick: dbClick_g,   
  308.             pageBarPlugins: [new Ext.ux.Andrie.pPageSize({   
  309.                 beforeText: '每页显示',   
  310.                 afterText: '条'  
  311.             })]   
  312.         });   
  313.         if (this.MYBugs) {   
  314.             this.filters.getFilter('assign').setValue(CURRENTUSERID);   
  315.             this.filters.getFilter('assign').setActive(truetrue);   
  316.             this.filters.getFilter('status').setValue(0);   
  317.             this.filters.getFilter('status').setActive(truetrue);   
  318.         } else {   
  319.   
  320.             this.filters.clearFilters();   
  321.             this.bugsGrid.reload();   
  322.         }   
  323.         Ext.apply(this, {   
  324.             title: this.title,   
  325.             iconCls: 'tabs',   
  326.             autoScroll: false,   
  327.             id: 'BugList_tab',   
  328.             layout: 'fit',   
  329.             items: this.bugsGrid,   
  330.             closable: true  
  331.         });   
  332.         //调用父类构造函数(必须)   
  333.         module.superclass.initComponent.apply(this, arguments);   
  334.     }   
  335. });  
   

可以看到在这个模块中可以调用 传过来的参数

 

 

Js代码 复制代码 收藏代码
  1. {   
  2. title:name,   
  3. MYBugs:false  
  4. }  


现在关键是 newModule 的实现了 ,也很简单 ,就是 ajax把 模块类区过来 ,new 一下 就是一个新的模块了 不过要注意一下缓存这个模块类的定义

 

Js代码 复制代码 收藏代码
  1. Ext.namespace("Ext.ux.yiminghe.framework.core");   
  2.   
  3. Ext.ux.yiminghe.framework.core.newModule = function(config) {   
  4.     //模块类的名字   
  5.     var moduleId = config.moduleId;   
  6.     //主Tab名字   
  7.     var tabPanel = config.tabPanel;   
  8.     //加载模块类的地址   
  9.     var moduleURL = config.moduleURL;   
  10.     //模块实例tab的id   
  11.     var realId = config.realId || moduleId;   
  12.     //缓存模块   
  13.     tabPanel.uxmodules = tabPanel.uxmodules || {};   
  14.     //模块实例的配置参数   
  15.     var moduleParams = config.moduleParams || {};   
  16.   
  17.     if (tabPanel.findById(realId)) {   
  18.         tabPanel.findById(realId).show();   
  19.         //如果已经载入该Tab ,则调用调整函数   
  20.         if (config.existCallBack)   
  21.         config.existCallBack(tabPanel.findById(realId));   
  22.         return;   
  23.     }   
  24.     if (tabPanel.uxmodules[moduleId]) {   
  25.         var module = tabPanel.uxmodules[moduleId];   
  26.         var moduleInstance = new module(moduleParams);   
  27.         var newCmp = tabPanel.add(moduleInstance);   
  28.         tabPanel.doLayout();   
  29.         tabPanel.setActiveTab(newCmp);   
  30.         return;   
  31.     }   
  32.     tabPanel.loadMask.show();   
  33.     Ext.Ajax.request(   
  34.     {   
  35.         method: 'GET',   
  36.         disableCaching: false,   
  37.         //utf-8 编码   
  38.         url: moduleURL,   
  39.         success: function(response) {   
  40.             var module = eval(response.responseText);   
  41.             tabPanel.uxmodules[moduleId] = module;   
  42.             var moduleInstance = new module(moduleParams);   
  43.             var newCmp = tabPanel.add(moduleInstance);   
  44.             tabPanel.doLayout();   
  45.             tabPanel.setActiveTab(newCmp);   
  46.             tabPanel.loadMask.hide();   
  47.         }   
  48.     }   
  49.     );   
  50. }  
 

 

总结一下流程:

 

1.请求一段 javascript 代码(定义一个Panel子类)

2.eval 出类型 T

3.得到新类型的实例 instance = new T
4.总控的tabpnel add instance 就可以了。