在我以前寫的一篇文章ExtJS4+Servlet/Struts2+JSON+accordion布局動態Ext.tree.Panel菜單,大家都對Ext.tree.Panel組件和Ext.tab.Panel組件相結合起來比較困惑。對於Ext.tree.Panel的非同步載入也有問題。寫這篇文章分享我對Ext開發的一些做法和認識。談談自己如何構建Ext應用程式框架的,下面讓大家看看:
- 這個圖的左邊是一個樹,這個樹的結構是從資料庫通過非同步方式拿出來的,資料格式是JSON。什麼非同步呢?就是載入父節點而不載入子節點,需要的時候再去載入子節點,從而節省數資源。
- 圖的上面是一個很簡單的應用程式名稱,下面有個工具列,展示登入人,系統時間和退出按鈕等一些組件。
- 圖的右邊是一個標籤頁,這個地方主要是使用者的操作介面,這裡是樹控制項的一些資料來產生標籤頁的。
這個項目是從我的那篇文章中擴充過來的,增加的資料庫的部分。資料庫是MYSQL,資料庫很簡單就只是一張表,表名是resource: 這裡面欄位比較簡單,
- id:主鍵ID
- component:一個Ext擴充類或者是調用的頁面,說白了就是你要讓使用者看到的內容
- descriptio:描述,與業務關鍵,純屬冗餘
- iconCls:樹節點顯示的表徵圖
- text:樹節點顯示的名稱
- sort:排序用的
- type:資源的類型,COMPONENT/URL,是組件的形式或者是URL
- parent_id:父節點
- leaf:是否是根節點
這個是資料表結構,現在我們看下JS實現代碼:
Ext.Loader.setConfig({enabled : true});Ext.Loader.setPath({'Ext.ux' : 'ext4/ux','Ext.app' : 'ext4/app'});Ext.require(['Ext.app.Portlet', 'Ext.app.PortalColumn', 'Ext.app.PortalPanel','Ext.app.PortalDropZone', 'Ext.ux.TabReorderer','Ext.ux.TabCloseMenu']);
這裡配置Ext動態載入功能,並引入了一些需要的Ext類,如果大家對Ext動態載入不怎麼瞭解,大家可以去看下黃燈橋老師的文章:在應用中使用Ext Loader,這裡對Ext的動態載入用詳細的介紹,我在這裡就不在贅述。下面看下應用的整體布局,整個架構一共三個組件,上面的為:title,左邊的為:tree,右邊的為:tab,下面看看這些組件的實現,先看title:
var title = Ext.create("Ext.panel.Panel", {height : 80,html : '業務基礎平台',region : 'north',split : true,bbar : [{iconCls : 'icon-user',text : '管理員'},'-',{text : Ext.Date.format(new Date(),'Y年m月d日')},'->',{text : '退出',iconCls : 'icon-logout'}],bodyStyle : 'backgroud-color:#99bbe8;line-height : 50px;padding-left:20px;font-size:22px;color:#000000;font-family:黑體;font-weight:bolder;' +'background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(153,187, 232, 0.4) ), color-stop(50%, rgba(153, 187, 232, 1) ),color-stop(0%, rgba(153, 187, 232, 0.4) ) )'});
這個是title,這個組件很簡單,主要是顯示了“業務基礎平台”的系統名稱,並配置了相關的樣式。並定義了一個bbar,用於顯示使用者名稱,目前時間和退出按鈕等資訊。下面看tab:
var tab = Ext.create('Ext.tab.Panel', {activeTab : 0,enableTabScroll : true,animScroll : true,border : true,autoScroll : true,region : 'center',split : true,items : [{iconCls : 'icon-activity',title : '平台首頁',xtype:'portalpanel',layout:'column',items : [{xtype : 'portalcolumn',columnWidth : 0.7, items:[{ title: '新聞動態',height : 150,iconCls : 'icon-news' }, {title: '最新通知',height : 150, iconCls : 'icon-notice' }, {title: '業績報表',height : 150, iconCls : 'icon-chart'}] },{ xtype : 'portalcolumn', columnWidth : 0.3, items:[{ title: '功能連結', height : 150, iconCls : 'icon-link'}, {title: '待辦事項',height : 150,iconCls : 'icon-note' }, {title: '郵件清單', height : 150,iconCls : 'icon-email-list'}] }]}],plugins: [Ext.create('Ext.ux.TabReorderer'), Ext.create('Ext.ux.TabCloseMenu',{ closeTabText: '關閉面板', closeOthersTabsText: '關閉其他', closeAllTabsText: '關閉所有' })]});
這裡我們定義了一個tabpanel,一些很普通的配置,大家可以去看官方文檔。這個代碼裡面有關鍵的兩個部分:
- 我們定義了一個portalpanel,這個是Ext的一個擴充應用,這個是可以允許使用者進行排版的,大家可以看看效果:
- 還有兩個外掛程式:Ext.ux.TabReorderer,這個是用來標籤拖動的,Ext.ux.TabCloseMenu,這個是標籤的右鍵菜單,用來關閉標籤頁。
下面看看左邊樹面板的實現,大家可能對這段代碼比較熟悉,關鍵是accordion布局,就不多做解釋:
var tree = Ext.create("Ext.panel.Panel", {region : 'west',title : "系統功能表",width : 250,iconCls : "icon-tree",autoScroll : false,layout : 'accordion',collapsible : true,layoutConfig : {animate : true},split : true});
下面我們將這些組件放在viewport組件裡面,展示出來:
Ext.create('Ext.container.Viewport',{layout : 'border',items : [title,tab,tree],listeners : {afterrender : function(){Ext.getBody().mask('正在載入系統功能表....');ajax({url : "app",// 擷取面板的地址params : {action : "list"},callback : addTree});}}}); 通過這段代碼的實現,將組件放入到頁面當中,這裡可能大家需要看看ext的布局方面的知識。大家注意了,在這段代碼中我們註冊了一個afterender的事件,這個事件的主要作用是,在組件渲染完成之後,去擷取系統功能表,ajax方法就是發送一個請求到後台獲得樹面板的資料,下面我們看看伺服器端的實現,伺服器端是用java寫的:
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {this.doPost(request, response);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String action = request.getParameter("action");initHeader(response);if (action.equals("list")) {// 擷取屬面板列表renderText(this.getTreePanelList(), response);} else if (action.equals("node")) {renderText(this.getTreeNodeList(request.getParameter("id")),response);}}public String getTreePanelList() {String sql = "select t.id, t.text, t.component, "+ " t.description, t.type, t.iconCls, t.sort "+ " from resource t where t.parent_id is null";return BaseDAO.findBySql(sql).toString();}public String getTreeNodeList(String id) {String sql = "select t.id, t.text, t.component, "+ " t.description, t.type, t.iconCls, t.sort,t.leaf "+ " from resource t where t.parent_id = '" + id + "'";return BaseDAO.findBySql(sql).toString();}
這段代碼的實現的是,通過參數判斷是擷取樹面板還是樹節點,BaseDAO.findBySql方法將返回的結果集轉換成一個List<JSONObject>對象,獲得資料後發送到頁面,這裡面有兩個獲得資料的方法:
- getTreePanelList,擷取樹面板,這裡的邏輯判斷是沒有父節點的資料
- getTreeNodeList,擷取樹節點,通過父節點尋找子節點
在ajax方法中註冊了一個回呼函數,addTree,用於添加樹面板:
function addTree(data) {Ext.getBody().unmask();for (var i = 0; i < data.length; i++) {tree.add(Ext.create("Ext.tree.Panel", {title : data[i].text,iconCls : data[i].iconCls,//useArrows: true,autoScroll : true,rootVisible : false,viewConfig : {loadingText : "正在載入..."},store : createStore(data[i].id),listeners : {afterlayout : function() {if (this.getView().el) {var el = this.getView().el;var table = el.down("table.x-grid-table");if (table) {table.setWidth(el.getWidth());}}},itemclick : function(view,node){if (node.isLeaf()) {if(node.data.type === 'URL'){var panel = Ext.create('Ext.panel.Panel',{title : node.data.text,closable : true,iconCls : 'icon-activity',html : '<iframe width="100%" height="100%" frameborder="0" src="http://www.baidu.com"></iframe>'});tab.add(panel);tab.setActiveTab(panel);}else if(node.data.type === 'COMPONENT'){var panel = Ext.create(node.data.component,{title : node.data.text,closable : true,iconCls : 'icon-activity'});tab.add(panel);tab.setActiveTab(panel);}}}}}));tree.doLayout();}}var model = Ext.define("TreeModel", { // 定義樹節點資料模型extend : "Ext.data.Model",fields : [{name : "id",type : "string"},{name : "text",type : "string"},{name : "iconCls",type : "string"},{name : "leaf",type : "boolean"},{name : 'type'},{name : 'component'}]});var createStore = function(id) { // 建立樹面板資料來源var me = this;return Ext.create("Ext.data.TreeStore", {defaultRootId : id, // 預設的根節點idmodel : model,proxy : {type : "ajax", // 擷取方式url : "app?action=node" // 擷取樹節點的地址},clearOnLoad : true,nodeParam : "id"// 設定傳遞給背景參數名,值是樹節點的id屬性});};
這段代碼在我的那片文章中由說明,在這裡就不再贅述,下面大家看看產生好的樹面板的效果:
就這樣樹空間就產生好了,大家注意在上邊的addTree方法的那段代碼中,我們註冊了一個itemclick事件,itemclick會在點擊樹節點的時候觸發:
itemclick : function(view,node){if (node.isLeaf()) { //判斷是否是葉子節點if(node.data.type === 'URL'){ //判斷資源類型var panel = Ext.create('Ext.panel.Panel',{title : node.data.text,closable : true,iconCls : 'icon-activity',html : '<iframe width="100%" height="100%" frameborder="0" src="http://www.baidu.com"></iframe>'});tab.add(panel);tab.setActiveTab(panel);}else if(node.data.type === 'COMPONENT'){var panel = Ext.create(node.data.component,{title : node.data.text,closable : true,iconCls : 'icon-activity'});tab.add(panel);tab.setActiveTab(panel);}}}
這裡的商務邏輯是,判斷點擊的節點是否是葉子節點,如果在葉子節點的話再判斷節點的類型,如果是URL,我這裡做了簡單的處理,嵌套百度到tab當中,如果是COMPONENT的話,建立對應組件,添加到tab組件當中。:
grid組件 這裡有幾個要注意的地方:
- 建立組件並添加後必須調用tab組件的setActiveTab方法來啟用組件,讓其顯示出來
- Ext.create('class')方法,如果有定義這個class,Ext會直接建立,如果沒有Ext會通過配置的動態載入的規則進行載入
- 如果要調用node.data裡面的屬性,一定要在store使用的model裡面進行定義,否則就是一個undefined
至此,這個平台都搭建就講完了,文采不好,希望大家海涵!!
http://download.csdn.net/detail/leecho571/4307693 執行個體下載,裡面有個app.sql的資料庫檔案,用mysql資料庫匯入即可 看文章評論一下是美德,你的評論是我最大的動力!!期待你的意見!!
上一篇:Ext4+Servlet+HTML5實現即時擷取檔案上傳進度、本地預覽、檔案拖拽上傳的相簿執行個體
下一篇:Ext.form.field.ComboBox結合Servlet、JSON實現AutoComplete
-
頂
-
19
-
踩
-
0