運行效果:
此文介紹了根據操作左側菜單在右面板展示相應內容。
一、主頁
先看一下跳轉主頁的方式:由在webapp根目錄下的index.jsp跳轉至demo的index.jsp
下面是demo的index.jsp的代碼
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% response.setHeader("Pragma","No-cache"); response.setHeader("Cache-Control","no-cache"); response.setHeader("Expires","0"); request.setCharacterEncoding("UTF-8"); //String webRoot = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/"; %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>首頁</title> <link href="../ExtJS4.2/resources/css/ext-all-neptune-rtl.css" rel="stylesheet"> <link href="../ExtJS4.2/css/icon.css" rel="stylesheet"> <script src="../ExtJS4.2/ext-all.js"></script> <script src="../ExtJS4.2/locale/ext-lang-zh_CN.js"></script> <script type="text/javascript" src="js/localXHR.js"></script> <script type="text/javascript" src="js/index.js"></script> </head> <body> <div id="north-div" style="height: 73px; background-color: #101010;"><img alt="思考者日記網|束洋洋個人博客" src="image/shuyangyang_01.jpg"></div> <div id="south-div" align="center">Copyright by 束洋洋© www.shuyangyang.com.cn</div> <div id="div2"></div> </body> </html>
看樣看到此頁面在引用文件的地方會加載2個自定義的js,在body處定義了頁面所包含的兩個dom元素。
先貼出筆者看不懂的localXHR.js
if (document.location.protocol == 'file:') { Ext.override(Ext.data.Connection, { parseStatus: function() { return { success: true, isException: false }; } }); }
然后是index.js
Ext.Loader.setConfig({ enabled : true }); Ext.Loader.setPath({ 'Ext.ux' : '../ExtJS4.2/ux'//設置命名空間的路徑 }); Ext.require(['Ext.ux.TabCloseMenu']);//動態加載 Ext.onReady(function() { var rightPanel = Ext.create('Ext.tab.Panel', { activeTab : 0, border : false, autoScroll : true, //iconCls:'Applicationviewlist', region : 'center', items : [{ title : '首頁', iconCls: 'House', html: '<iframe frameborder="no" border=0 height="100%" width="100%" src="blank.jsp" scrolling="auto"></iframe>', }], plugins: [Ext.create('Ext.ux.TabCloseMenu',{//選項卡關閉插件 closeTabText: '關閉當前',//The text for closing the current tab. closeOthersTabsText: '關閉其他',//The text for closing all tabs except the current one. closeAllTabsText: '關閉所有'//The text for closing all tabs. })] }); var tree = Ext.create("Ext.panel.Panel", { height : '70%',//設置高度 region : 'north', layout : { // layout-specific configs go here type : 'accordion', titleCollapse : true,//允許通過點擊標題欄的任意位置來展開/收縮子項Panel animate : true,// 動畫切換效果 activeOnTop : false // 折疊展開是否改變菜單順序 }, layoutConfig : { animate : true }, split : true }); // 左邊下部Panel var detailsPanel = { id : 'details-panel', iconCls : "User", collapsible : true, // 是否折疊 title : '信息', region : 'center', bodyStyle : 'padding-bottom:15px;background:#eee;', autoScroll : true, html : '<p class="details-info">用戶名:束洋洋<br />部 門:管理部<br />登錄IP:156.15.26.101</p>' }; // 左邊下部Panel結束 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 : 'url',type:"string"}, {name : 'description',type:"string"}] }); //組建樹,返回Ext.tree.Panel var buildTree = function(json) { return Ext.create('Ext.tree.Panel', { rootVisible : false,//false,隱藏根節點。 border : false,//隱藏此樹面板的邊框 lines:false,//false,樹用的線置為disable。 autoScroll:true,//自動顯示滾動條 useArrows:true, store : Ext.create('Ext.data.TreeStore', {//(必須的) Store樹的數據源. 一個TreePanel必須綁定一個Ext.data.TreeStore。 model : model,//定義當前store對象的Model數據模型 root : {//當前store的根節點。 expanded : true,//展開根節點。(因為根節點被設置為隱藏,所以在此可以不用設置此屬性) children : json.children//子節點數組。 } }), listeners : {//配置監聽 'itemclick' : function(view, record, item, index, e) {//選項的單擊事件。單擊選項時觸發。--Ext.view.View-event-itemclick var leaf = record.get('leaf');//獲取當前選項的leaf——是否為葉子節點 //var typeId = record.get("TYPE_ID"); var text = record.get('text');//獲取當前選項的文本 var icon = record.get('iconCls');//獲取當前選項的圖標 var url = record.get('url');//獲取當前選項的地址 if (leaf) { //判斷點擊的是否是葉子節點,如果是,創建一個Panel var panel = Ext.create('Ext.panel.Panel',{ title : text,//標題 closable : true,//該屬性配置為true,這個窗體的'close'工具按鈕便會展現出來並且允許用戶通過點擊這個按鈕來關閉這個窗體,false則相反。 iconCls : icon,//左側圖標 html : '<iframe width="100%" height="100%" frameborder="0" src='+url+'></iframe>'//一個 HTML片段——這個Panel的內容 }); rightPanel.add(panel);//右面板(Ext.tab.Panel)添加此組件 rightPanel.setActiveTab(panel);//使此組件處於活動狀態 } /*var id = record.get('id'); var text = record.get('text'); var leaf = record.get('leaf'); if (leaf) { alert('id-' + id + ',text-' + text + ',leaf-' + leaf); }*/ }, scope : this//The scope (this reference) in which the handler is executed. Defaults to the browser window. } }); }; // 整體架構容器 Ext.create("Ext.container.Viewport", { layout : 'border', items : [ { region : 'north',//北方 contentEl : 'north-div',//指定一個已存在的HTML元素, 或者一個已存在HTML元素的 id , 它們將被用作當前組件的內容. height : 73, bodyStyle : 'background-color:#BBCCEE;' }, { region : 'south',//南方 contentEl : 'south-div', height : 20, bodyStyle : 'background-color:#BBCCEE;' }, { layout : 'border', title : '菜單', id : 'layout-browser', region : 'west',//西方 border : false, split : true, margins : '2 0 5 5', width : 200, //minSize : 10,//無效設置 //maxSize : 50,//無效設置 autoScroll : false, collapsible : true, // 是否折疊 //iconCls : "Application", items : [ tree, detailsPanel ]//包含樹面板、個人簡介面板。注:子組件的相對位置在子組件里設置,如在tree中設置了height屬性,就指定了tree的相對高度。 }, rightPanel ], listeners : {//監聽。這里用來添加樹面板里的菜單 afterrender : function() {//在組件渲染完成之后觸發.Ext.AbstractComponent Ext.getBody().mask('正在加載系統菜單....');//顯示遮罩層 Ext.Ajax.request({//向服務端發送ajax請求 url:'../../menu/showMenu',//請求地址 success : function(response) {//成功響應的回調函數。response:包含了響應數據的XMLHttpRequest對象. Ext.getBody().unmask();//隱藏先前應用的遮罩層. var json = Ext.JSON.decode(response.responseText);//獲取返回的文本並解析為json格式。Ext.JSON.decode(..):解碼(解析)JSON字符串對象。 if(json.code == 'OK'){ Ext.each(json.data, function(el) {//迭代一個數組或是可迭代的值,在每個元素上調用給定的回調函數 var panel = Ext.create('Ext.panel.Panel', {//創建一個Panel id : el.id,//定義id title : el.text,//定義標題 iconCls:el.iconCls,//定義圖標 leaf :el.leaf,//定義leaf。Ext.data.NodeInterface-cfg-leaf:設置為true表明本節點沒有子節點。 不會為本節點渲染展開圖標或箭頭。 layout : 'fit'//定義布局。fit:當容器只包含一個子元素時, 子元素自動填滿容器 }); panel.add(buildTree(el));//當前Panel添加由此節點的子節點所創建的樹面板 tree.add(panel);//tree(1個Panel)添加當前Panel }); }else{} },failure : function(request) { Ext.MessageBox.show({ title : '操作提示', msg : "連接服務器失敗", buttons : Ext.MessageBox.OK, icon : Ext.MessageBox.ERROR }); }, method : 'post'//請求的方式 }); } } }); });
分析:
1.插件。當前頁面使用了選項卡關閉插件(Ext.ux.TabCloseMenu),效果如下:
因此需要加載Ext.ux.TabCloseMenu類,如下:
Ext.Loader.setConfig({ enabled : true }); Ext.Loader.setPath({ 'Ext.ux' : '../ExtJS4.2/ux'//設置命名空間的路徑 }); Ext.require(['Ext.ux.TabCloseMenu']);//動態加載
這里有個小疑惑:采用Ext.require的方式加載類,還是“動態加載”嗎?因為從表面上看在加載index.js時就會加載Ext.ux.TabCloseMenu類。不管怎樣,這里把它加載就好。
2.頁面布局
2.1 整體布局:整體采用Ext.container.Viewport的布局方式,其內部子組件采用border的布局方式,如下片段代碼:
// 整體架構容器 Ext.create("Ext.container.Viewport", { layout : 'border', items : [ { region : 'north',//北方 contentEl : 'north-div',//指定一個已存在的HTML元素, 或者一個已存在HTML元素的 id , 它們將被用作當前組件的內容. height : 73, bodyStyle : 'background-color:#BBCCEE;' }, { region : 'south',//南方 contentEl : 'south-div', height : 20, bodyStyle : 'background-color:#BBCCEE;' }, { layout : 'border', title : '菜單', id : 'layout-browser', region : 'west',//西方 border : false, split : true, margins : '2 0 5 5', width : 200, //minSize : 10,//無效設置 //maxSize : 50,//無效設置 autoScroll : false, collapsible : true, // 是否折疊 //iconCls : "Application", items : [ tree, detailsPanel ]//包含樹面板、個人簡介面板。注:子組件的相對位置在子組件里設置,如在tree中設置了height屬性,就指定了tree的相對高度。 }, rightPanel ],
當Ext.container.Viewport采用border的布局方式,那么子組件的方位(東、南、西、北/中心)由子組件的region屬性指定。上面的rightPanel組件在上面雖看不出,但在其內部定義了region : 'center'——在中心顯示。
2.2 樹面板(TreePanel)布局
此文中的樹面板布局相對其他組件的布局相對復雜,為了方便說明,下面將樹面板中accordion的布局方式去掉:
var tree = Ext.create("Ext.panel.Panel", { height : '70%',//設置高度 region : 'north', /*layout : { // layout-specific configs go here type : 'accordion', titleCollapse : true,//允許通過點擊標題欄的任意位置來展開/收縮子項Panel animate : true,// 動畫切換效果 activeOnTop : false // 折疊展開是否改變菜單順序 },*/ layoutConfig : { animate : true }, split : true });
去掉以后的顯示效果:
上圖說明了樹面板的結構。在創建樹面板的過程中,首先根據菜單的一級菜單創建一個Panel,然后再添加由此一級菜單的子菜單所創建的TreePanel,最后由tree(一個Panel)再把這個Panel添加進去。相應的代碼如下:
Ext.each(json.data, function(el) { var panel = Ext.create('Ext.panel.Panel', {//創建一個Panel id : el.id, title : el.text, iconCls:el.iconCls, leaf :el.leaf, layout : 'fit' }); panel.add(buildTree(el));//當前Panel添加TreePanel tree.add(panel);//tree添加當前Panel });
3.事件
在index.js涉及了2個事件:
一是在創建Ext.container.Viewport容器時所設置的‘afterrender’事件,這個事件用於向服務端發送請求以往tree面板中添加菜單;下面看一下代碼 Ext.container.Viewport
listeners : {//監聽。這里用來添加樹面板里的菜單 afterrender : function() {//在組件渲染完成之后觸發。--Ext.container.Viewport Ext.getBody().mask('正在加載系統菜單....'); Ext.Ajax.request({ url:'../../menu/showMenu', success : function(response) {//成功響應的回調函數。response:包含了響應數據的XMLHttpRequest對象. Ext.getBody().unmask();//隱藏先前應用的遮罩層. var json = Ext.JSON.decode(response.responseText);//獲取返回的文本並解析為json格式。Ext.JSON.decode(..):解碼(解析)JSON字符串對象。 if(json.code == 'OK'){ Ext.each(json.data, function(el) {//迭代一個數組或是可迭代的值,在每個元素上調用給定的回調函數 var panel = Ext.create('Ext.panel.Panel', { id : el.id, title : el.text, iconCls:el.iconCls, leaf :el.leaf, layout : 'fit' }); panel.add(buildTree(el));//當前Panel添加TreePanel tree.add(panel);//tree添加當前Panel }); }else{} },failure : function(request) { Ext.MessageBox.show({ title : '操作提示', msg : "連接服務器失敗", buttons : Ext.MessageBox.OK, icon : Ext.MessageBox.ERROR }); }, method : 'post'//請求的方式 }); } }
注:事件名可以加單引號'',也可以不加.
二是在創建樹面板中中Ext.data.TreeStore的‘itemclick’事件——此事件是用來在點擊左側菜單時,向右邊的面板(選項卡)添加一個選項卡面板,下面再看一下這里的代碼
listeners : {//配置監聽 'itemclick' : function(view, record, item, index, e) {//選項的單擊事件。單擊選項時觸發。--Ext.tree.Panel var leaf = record.get('leaf'); //var typeId = record.get("TYPE_ID"); var text = record.get('text'); var icon = record.get('iconCls'); var url = record.get('url');//獲取當前選項的地址 if (leaf) { //判斷點擊的是否是葉子節點,如果是,創建一個Panel var panel = Ext.create('Ext.panel.Panel',{ title : text,//標題 closable : true,//該屬性配置為true,這個窗體的'close'工具按鈕便會展現出來並且允許用戶通過點擊這個按鈕來關閉這個窗體,false則相反。 iconCls : icon,//左側圖標 html : '<iframe width="100%" height="100%" frameborder="0" src='+url+'></iframe>'//一個 HTML片段——這個Panel的內容 }); rightPanel.add(panel);//右面板(Ext.tab.Panel)添加此組件 rightPanel.setActiveTab(panel);//使此組件處於活動狀態 } }, scope : this//The scope (this reference) in which the handler is executed. Defaults to the browser window. }
這個‘itemclick’事件來自於Ext.tree.Panel,從此事件可知,當點擊左邊的菜單時,首先會判定該菜單是否為葉子節點,如果是,則會創建一個Panel,這個Panel含有標題,圖標,html等屬性,然后右選項卡面板會將此面板添加進去並將其設置為可活動的。需注意的是,由於所添加的Panel里的html屬性是一個iframe,所以在渲染時會把iframe里的src所在資源頁面包含進來。
功能
一、用戶管理
當點擊菜單選項中的“用戶管理”,那么在rightPanel(選項卡面板)會添加一個子選項卡,此子選項卡有一個html配置,它是一個iframe,其中的src為:/demo/UserMan/index.jsp——即此菜單的url值。這樣“用戶管理”這個子選項卡就會包含這個頁面。下面看一下這個頁面:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% response.setHeader("Pragma","No-cache"); response.setHeader("Cache-Control","no-cache"); response.setHeader("Expires","0"); request.setCharacterEncoding("UTF-8"); //String webRoot = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/"; %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>用戶管理</title> <link href="../../ExtJS4.2/resources/css/ext-all-neptune-rtl.css" rel="stylesheet"> <link href="../../ExtJS4.2/css/icon.css" rel="stylesheet"> <script src="../../ExtJS4.2/ext-all.js"></script> <script src="../../ExtJS4.2/locale/ext-lang-zh_CN.js"></script> <script type="text/javascript" src="../js/localXHR.js"></script> <script type="text/javascript" src="../js/userMan.js"></script> </head> <body> </body> </html>
可以看出這個頁面除了引用文件說明什么也沒有,這就對了,因為所有的內容在userMan.js中。下面看一下userMan.js
//引入擴展組件 Ext.Loader.setConfig({enabled: true}); Ext.Loader.setPath('Ext.ux', '../../ExtJS4.2/ux/'); Ext.require([ 'Ext.data.*', 'Ext.grid.*', 'Ext.util.*', 'Ext.tip.QuickTipManager', 'Ext.ux.data.PagingMemoryProxy', 'Ext.ux.ProgressBarPager' ]); Ext.onReady(function() { //創建列 var columns = [ {xtype: 'rownumberer'},//創建Ext.grid.RowNumberer的實例。Ext.grid.RowNumberer:它是一個為每行提供編號的列。 {header:'編號',dataIndex:'id',hidden: true}, {header:'用戶名',dataIndex:'name'}, {header:'年齡',dataIndex:'age'},//年齡 {header:'性別',dataIndex:'sex',renderer:function(value){ if(value=='男'){ return "<span style='color:green;font-weight:bold';>男</span>"; } else { return "<span style='color:red;font-weight:bold';>女</span>"; } }}, {header:'地址',dataIndex:'address'}, {header:'身份證號碼',dataIndex:'cardId',width:150}, {header:'角色',dataIndex:'roleId'}, {header:'部門',dataIndex:'deptId'} ]; //創建倉庫 var store = Ext.create("Ext.data.Store",{ pageSize:20, //每頁顯示幾條數據 //采用代理方式向服務端發送請求,獲取數據 proxy:{ type:'ajax', url:'/user/showUser', reader:{ type:'json', totalProperty:'total',//總記錄數 root:'data', //數據 idProperty:'id' //主鍵 } }, fields:[ //字段。reader是根據這里的字段信息來解析返回的數據的。 {name:'id'}, //mapping:0 這樣的可以指定列顯示的位置,0代表第1列,可以隨意設置列顯示的位置 {name:'name'}, {name:'age'}, {name:'sex'}, {name:'address'}, {name:'cardId'}, {name:'roleId'}, {name:'deptId'} ] }); var sm = Ext.create('Ext.selection.CheckboxModel'); var grid = Ext.create("Ext.grid.Panel",{ region: 'center', border: false, store: store, selModel: sm,//選擇模式是“復選框” columns: columns, region: 'center', //框架中顯示位置,單獨運行可去掉此段 loadMask:true, //顯示遮罩和提示功能,即加載Loading…… forceFit:true, //自動填滿表格 columnLines:false, //列的邊框 rowLines:true, //設置為false則取消行的框線樣式 dockedItems: [{ xtype:'toolbar', dock:'top', displayInfo: true, items:[{ xtype: 'textfield',name: 'name',fieldLabel: '用戶名',labelAlign:'left',labelWidth:65}, { xtype: 'textfield',name: 'dept',fieldLabel: '部門',labelAlign:'left',labelWidth:35}, { xtype: 'textfield',name: 'role',fieldLabel: '角色',labelAlign:'left',labelWidth:35}, { xtype: 'button', text: '查詢',iconCls:'Usermagnify'}, { xtype: 'button', text: '顯示全部',iconCls:'Applicationformmagnify'}] },{ xtype:'toolbar', dock:'top', displayInfo: true, items:[ '-', { xtype: 'button', text: '增加用戶',iconCls:'Useradd', listeners: { click:function(){ Ext.Msg.alert("增加用戶","增加用戶啦"); } } },'-', { xtype: 'button', id:'editUser', text: '編輯用戶',disabled:true,iconCls:'Useredit',//disabled:true 該button處於禁用狀態 listeners: { click:function(){ Ext.Msg.alert("編輯用戶","編輯用戶啦"); } }},'-', { xtype: 'button', id:'delUser', text: '刪除用戶',disabled:true,iconCls:'Userdelete', listeners: { click:function(){ Ext.Msg.alert("刪除用戶","刪除用戶啦"); } }},'-', { xtype: 'button', id:'allotUser', text: '分配角色',disabled:true,iconCls:'Usergo', listeners: { click:function(){ Ext.Msg.alert("分配","分配用戶啦"); } }}, { xtype: 'button', text: '導入',iconCls:'Databasecopy', listeners: { click:function(){ Ext.Msg.alert("導入","導入用戶啦"); } }},'-', { xtype: 'button', text: '導出',iconCls:'Pagewhiteoffice',menu:{//菜單屬性 items:[{//子組件的默認xtype是panel text:'導出EXCEL', iconCls:'Pageexcel', listeners: { click:function(){ Ext.Msg.alert("導出Excel","導出Excel"); } } },{ text:'導出CSV', iconCls:'Pagegreen', listeners: { click:function(){ //Ext.getCmp('editUser').setDisabled(true); Ext.Msg.alert("導出CSV","導出CSV"); } } }] }},'-', { xtype: 'button', text: '打印',iconCls:'Printer', listeners: { click:function(){ Ext.Msg.alert("打印","打印"); } }}], },{ xtype: 'pagingtoolbar',//分頁工具欄 store: store, // GridPanel使用相同的數據源 dock: 'bottom', displayInfo: true, plugins: Ext.create('Ext.ux.ProgressBarPager'),//分頁進度條 emptyMsg: "沒有記錄" //沒有數據時顯示信息 }] }); //加載數據 store.load({params:{start:0,limit:20}}); // 表格配置結束 //監聽表格(為表格的選擇模型添加selectionchange事件) grid.getSelectionModel().on({//getSelectionModel:返回grid的選擇模型。on:是addListener的簡寫方法 selectionchange: function(sm, selections) {//一個選項發生改變之后觸發。參數:selections:選擇的記錄 if (selections.length) {//如果有被選中的記錄,則‘修改用戶’、‘刪除用戶’、‘分配角色’三個按鈕設置為可用狀態 Ext.getCmp('editUser').setDisabled(false);//getCmp:返回指定id的組件 Ext.getCmp('delUser').setDisabled(false); Ext.getCmp('allotUser').setDisabled(false); } else {//反之,這三個按鈕設置為禁用狀態。 Ext.getCmp('editUser').setDisabled(true); Ext.getCmp('delUser').setDisabled(true); Ext.getCmp('allotUser').setDisabled(true); } } }); //表格右鍵菜單 var contextmenu = new Ext.menu.Menu({ id:'theContextMenu', items:[{ text:'增加用戶', iconCls:'Useradd', handler:function(){ Ext.Msg.alert("系統提示","增加用戶"); } },'-',{ text:'編輯用戶', iconCls:'Useredit', handler:function(){ Ext.Msg.alert("系統提示","編輯用戶"); } },'-',{ text:'刪除用戶', iconCls:'Userdelete', handler:function(){ Ext.Msg.alert("系統提示","刪除用戶"); } },'-',{ text:'分配角色', iconCls:'Usergo', handler:function(){ Ext.Msg.alert("系統提示","分配角色"); } },'-',{ text:'導入', iconCls:'Databasecopy', handler:function(){ Ext.Msg.alert("系統提示","導入"); } },'-',{ text:'導出', iconCls:'Pagewhiteoffice', menu:{ items:[{ text:'導出EXCEL', iconCls:'Pageexcel', listeners: { click:function(){ Ext.Msg.alert("導出Excel","導出Excel"); } } },{ text:'導出CSV', iconCls:'Pagegreen', listeners: { click:function(){ //Ext.getCmp('editUser').setDisabled(true); Ext.Msg.alert("導出CSV","導出CSV"); } } }] } },'-',{ text:'打印', iconCls:'Printer', handler:function(){ Ext.Msg.alert("系統提示","打印"); } }] }); //為表格添加右鍵菜單事件 grid.on("itemcontextmenu",function(view,record,item,index,e){ //on:addListener的簡寫方法. itemcontextmenu:選項的右鍵菜單事件 右鍵單擊選項時觸發。 e.preventDefault(); //阻止瀏覽器默認行為處理事件。--Ext.EventObject contextmenu.showAt(e.getXY()); //contextmenu在特定的XY位置顯示。 getXY:獲取事件的頁面坐標。--Ext.EventObject }); //為表格添加雙擊事件 grid.on("itemdblclick",function(grid, row){ Ext.Msg.alert("系統提示","你雙擊啦!ID為:"+row.data.id); }); // 整體架構容器 Ext.create("Ext.container.Viewport", { layout : 'border', autoHeight: true, border: false, items : [grid] }); });
分析:
1.布局:雖然只有一個子組件grid,但依然采用的是Viewport的布局方式。
2.插件
Extjs4.2加了很多拓展插件(4.1版本沒有),所在的命名空間為'Ext.ux',如下圖:
這里就用到了其中的一個插件:ProgressBarPager--分頁進度條,所以在此js需加載此類:
//引入擴展組件 Ext.Loader.setConfig({enabled: true}); Ext.Loader.setPath('Ext.ux', '../../ExtJS4.2/ux/'); Ext.require([ 'Ext.data.*', 'Ext.grid.*', 'Ext.util.*', 'Ext.tip.QuickTipManager', 'Ext.ux.data.PagingMemoryProxy', 'Ext.ux.ProgressBarPager' ]);
注:除了加載這個 'Ext.ux.ProgressBarPager'插件,對於其他的加載類筆者也不太明白為什么要加載?對於目前的功能,即使注釋掉也沒影響的,如下:
Ext.require([ /*'Ext.data.*', 'Ext.grid.*', 'Ext.util.*', 'Ext.tip.QuickTipManager', 'Ext.ux.data.PagingMemoryProxy',*/ 'Ext.ux.ProgressBarPager' ]);
可能是再編輯一些更復雜的功能會需要把。
3.xtype: 'rownumberer'
在創建表格時的第一列就創建了'rownumberer'這個對象,在Extjs中,xtype:'..'是很常見的寫法,它用於創建某個類的實例(有時沒有這個,一般默認的xtype是panel)組件,api解釋如下:
4.表格的事件
在顯示用戶數據的表格中涉及了2個事件:
一是某行是否被選中的事件,其定義如下:
//監聽表格(為表格的選擇模型添加selectionchange事件) grid.getSelectionModel().on({//getSelectionModel:返回grid的選擇模型。on:是addListener的簡寫方法 selectionchange: function(sm, selections) {//一個選項發生改變之后觸發。參數:selections:選擇的記錄 if (selections.length) {//如果有被選中的記錄,則‘修改用戶’、‘刪除用戶’、‘分配角色’三個按鈕設置為可用狀態 Ext.getCmp('editUser').setDisabled(false);//getCmp:返回指定id的組件 Ext.getCmp('delUser').setDisabled(false); Ext.getCmp('allotUser').setDisabled(false); } else {//反之,這三個按鈕設置為禁用狀態。 Ext.getCmp('editUser').setDisabled(true); Ext.getCmp('delUser').setDisabled(true); Ext.getCmp('allotUser').setDisabled(true); } } });
從以上代碼可看出,監聽表格的某行是否被選中所監聽的對象並不是表格本身,而是這個表格所屬的選擇模型(此表格的選擇模型是復選框),在其所屬的選擇模型上增加‘selectonchange’事件。
二是表格的右鍵菜單事件,如下:
//表格右鍵菜單 var contextmenu = new Ext.menu.Menu({ id:'theContextMenu', items:[{ text:'增加用戶', iconCls:'Useradd', handler:function(){ Ext.Msg.alert("系統提示","增加用戶"); } },'-',{ text:'編輯用戶', iconCls:'Useredit', handler:function(){ Ext.Msg.alert("系統提示","編輯用戶"); } },'-',{ text:'刪除用戶', iconCls:'Userdelete', handler:function(){ Ext.Msg.alert("系統提示","刪除用戶"); } },'-',{ text:'分配角色', iconCls:'Usergo', handler:function(){ Ext.Msg.alert("系統提示","分配角色"); } },'-',{ text:'導入', iconCls:'Databasecopy', handler:function(){ Ext.Msg.alert("系統提示","導入"); } },'-',{ text:'導出', iconCls:'Pagewhiteoffice', menu:{ items:[{ text:'導出EXCEL', iconCls:'Pageexcel', listeners: { click:function(){ Ext.Msg.alert("導出Excel","導出Excel"); } } },{ text:'導出CSV', iconCls:'Pagegreen', listeners: { click:function(){ //Ext.getCmp('editUser').setDisabled(true); Ext.Msg.alert("導出CSV","導出CSV"); } } }] } },'-',{ text:'打印', iconCls:'Printer', handler:function(){ Ext.Msg.alert("系統提示","打印"); } }] }); //為表格添加右鍵菜單事件 grid.on("itemcontextmenu",function(view,record,item,index,e){ //on:addListener的簡寫方法. itemcontextmenu:選項的右鍵菜單事件 右鍵單擊選項時觸發。 e.preventDefault(); //阻止瀏覽器默認行為處理事件。--Ext.EventObject contextmenu.showAt(e.getXY()); //contextmenu在特定的XY位置顯示。 getXY:獲取事件的頁面坐標。--Ext.EventObject });
從以上代碼可看出,在表格中設置右鍵呼出菜單的功能是先定義菜單項,然后為表格添加監聽,其事件就是“itemcontextmenu”。需注意的是,由於在window系統下有自帶的右鍵菜單事件,所以一般都要在處理函數中阻止默認的處理事件。
5.一個細節:menu的子組件的xtype默認是panel?
先貼出代碼:
{ xtype: 'button', text: '導出',iconCls:'Pagewhiteoffice',menu:{//菜單屬性 items:[{//子組件的默認xtype是panel text:'導出EXCEL', iconCls:'Pageexcel', listeners: { click:function(){ Ext.Msg.alert("導出Excel","導出Excel"); } } },{ text:'導出CSV', iconCls:'Pagegreen', listeners: { click:function(){ //Ext.getCmp('editUser').setDisabled(true); Ext.Msg.alert("導出CSV","導出CSV"); } } }] }},'-',
以上代碼的作用是設置按鈕並為它添加菜單——就是menu屬性,在button類的api這樣介紹此屬性:
上面代碼中menu的值就是一個菜單對象,它又包含2個子組件,在Ext.menu.Menu的api中解釋items說默認的子組件的xtype為panel,如下:
那么其中的text屬性應該存在於panel的配置選項中,可是查詢沒有,在menu中也沒有查詢到text屬性。然后全局查找:
覺得此屬性的來源比較靠譜是button類中的此屬性——畢竟此菜單的父容器就是button。解釋是:按鈕里的文字。
現在問題已確定了:items的子組件xtype是默認的panel嗎?下面把代碼修改成顯示的指定xtype為panel,如下:
items:[{//子組件的默認xtype是panel xtype:'panel', text:'導出EXCEL', iconCls:'Pageexcel', listeners: { click:function(menu,item){ console.log(menu); console.log(item); Ext.Msg.alert("導出Excel","導出Excel"); } } }
然后運行,不能正常顯示了:
再設置:xtype:'button',
也不能正常顯示:
再設置:xtype:'menu',
這一組件直接沒了:
最后去掉xtype這個配置,還原,通過調試來看一下是否能確定其身份:
控制台打印的menu的信息如下:
似乎也沒有任何跡象表明其身份。所以現在是很奇怪的:items中的兩個組件的text屬性屬於button類;其監聽中的click事件屬於menu類,那么它自己的xtype到底是什么呢?
二、部門管理
執行原理同上,這里直接貼dept.js
//引入擴展組件 Ext.Loader.setConfig({enabled: true}); Ext.Loader.setPath('Ext.ux', '../../ExtJS4.2/ux/'); Ext.require([ 'Ext.data.*', 'Ext.grid.*', 'Ext.util.*', 'Ext.tip.QuickTipManager', 'Ext.ux.data.PagingMemoryProxy', 'Ext.ux.ProgressBarPager' ]); Ext.onReady(function() { Ext.define("DeptModel", { extend: "Ext.data.TreeModel", fields: [ "id", "text", "status","description" ] }); var store = Ext.create("Ext.data.TreeStore",{ model: "DeptModel", proxy:{ type:'ajax', url:'../config/treegrid.json' ///dept/showDept } }); var columns = [{ text: '編號', flex: 1, dataIndex: 'id', hidden: true, sortable: true },{ xtype: 'treecolumn', //this is so we know which column will show the tree text: '名稱', flex: 2, sortable: true, dataIndex: 'text' },{ text: '狀態', flex: 1, dataIndex: 'status', sortable: true,renderer:function(value){ if(value==0){ return "<span style='color:green;font-weight:bold';>正常</span>"; } else { return "<span style='color:red;font-weight:bold';>停用</span>"; } } },{ text: '描述', flex: 1, dataIndex: 'description', sortable: true }]; //var sm = Ext.create('Ext.selection.CheckboxModel'); var tree = Ext.create('Ext.tree.Panel', { renderTo: Ext.getBody(), rootVisible: false, region: 'center', //selModel: sm, loadMask:true, //顯示遮罩和提示功能,即加載Loading…… columnLines:false, //列的邊框 border: false, forceFit:true, //自動填滿表格 rowLines:true, //設置為false則取消行的框線樣式 columns: columns, store:store }); // 整體架構容器 Ext.create("Ext.container.Viewport", { layout : 'border', autoHeight: true, border: false, items : [tree] }); });
數據源:treegrid.json
{ "text": ".", "children": [ { "id": "1", "text": "總部", "status": 0, "expanded": true, "description":"總部根節點", "leaf":false, "children": [ { "id": "2", "text": "開發部", "status": 0, "description":"開發部", "expanded": true, "children": [ { "id": "3", "text": "測試部", "status": 1, "description":"開發部", "leaf": true }, { "id": "4", "text": "前端部", "status": 0, "description":"開發部", "leaf": true }, { "id": "5", "text": "質量部", "status": 1, "description":"開發部", "leaf": true, }, { "id": "6", "text": "版本控制部", "status": 0, "description":"開發部", "leaf": true, } ] }, { "id": "7", "text": "項目部", "status": 1, "description":"開發部", "expanded": true, "children": [ { "id": "8", "text": "實施部", "status": 0, "description":"開發部", "leaf": true }, { "id": "9", "text": "運維部", "status": 1, "description":"開發部", leaf:true } ] } ] },{ "id": "10", "text": "總部2", "status": 0, "expanded": true, "description":"總部根節點", "leaf":false, "children": [ { "id": "11", "text": "開發部2", "status": 0, "description":"開發部", "expanded": true, "children": [ { "id": "12", "text": "測試部2", "status": 1, "description":"開發部", "leaf": true }, { "id": "13", "text": "前端部2", "status": 0, "description":"開發部", "leaf": true }, { "id": "14", "text": "質量部2", "status": 1, "description":"開發部", "leaf": true, }, { "id": "15", "text": "版本控制部2", "status": 0, "description":"開發部", "leaf": true, } ] }, { "id": "16", "text": "項目部2", "status": 1, "description":"開發部", "expanded": true, "children": [ { "id": "17", "text": "實施部2", "status": 0, "description":"開發部", "leaf": true }, { "id": "18", "text": "運維部2", "status": 1, "description":"開發部", leaf:true } ] } ] } ] }