本文源碼位址:http://download.csdn.net/detail/xz2001/4944407
一、介紹與下載下傳
整個架構的整合中,ExtJS比較簡單,與NHibernate、Spring.NET幾乎沒有什麼關系,唯一需要的是JSON或XML格式資料。
在寫這篇檔案時,ExtJS的最新版是4.0.7,本文也就采用這個版本。
ExtJS4.0與2、3有明顯的差別,3.x向4.x的更新,不是2.x向3.x更新那樣簡單,4.x中整體性能有明顯提升。另外,4.x中使用了流行的MVC模式,還有懶加載的機制等等。
ExtJS官方下載下傳位址:http://www.sencha.com/products/extjs/download/
二、安裝部署
為了清晰項目結構,個人喜歡把所有js、css、img以及第三方用戶端架構都放在Web項目的Content目錄中。其中的css、主題暫時不需要,可以先清空,然後把extjs解壓後的目錄整個複制進來。如下圖:
這裡說一下,由于extjs架構中的檔案太多,複制進來的時候特别慢,我的電腦等了估計有5分鐘左右。是以,可以把extjs精簡一下,比如doc、examples等目錄删除,另外,也可以在VS解決方案資料總管中排除extjs整個目錄,這樣以後會快很多。
三、項目結構
既然使用了ExtJS4.o,肯定要用4.0中的MVC開發模式。在編寫之前,先看下我的目錄結構:
有過MVC開發經驗的應該一眼明白。事實上,MVC更多的是一種約定,比如:視圖放在子產品名稱的目錄下,系統會自動來這個目錄下搜尋。至于能不能放到别處,本人沒仔細研究,不過,ASP.NET MVC中的視圖是可以的,隻要重寫“WebFormViewEngine”類,詳細看這裡:http://blog.csdn.net/xz2001/article/details/7031756
另外,看一下Area的結構:
這裡大概說幾點:
1、ExtJS4.0中所有的資源檔案是動态加載的,具體可以了解"Ext Loader"加載機制;
2、ExtJS4.0項目是以子產品為機關進行開發,在ExtJS中是以命名空間展現的;
3、每個子產品的入口檔案是app.js,app中要聲明需要使用的控制器;
4、控制器中要聲明使用到的View、Model以及Store。理論上說,應該把所有事件的處理放在Controller中,就如在Struts、ASP.NET MVC中開發一樣,事件應該由控制器捕獲和處理,View僅僅負責渲染控件、顯示資料;
5、Model與Struts、ASP.NET MVC中的實體類差不多,但不同于領域模型中的領域對象,這裡的Model僅僅含有資料,不含有任何方法;
6、Store在ExtJS中扮演着資料源與Model之間的橋梁,通過與Proxy對象進行資料的CURD操作;
7、4.0中的視圖負責控件的渲染,實事上視圖中的代碼功能與之前的版本很相似。
四、編寫代碼
由于用到的js檔案較多,這裡我就直接上代碼了,不清楚的對應上面的截圖看一下。
1、app.js
Ext.application({
name: 'AM',
appFolder: '/Content/Manage/app',
controllers: [
'Menu',
'User'
],
autoCreateViewport: true
});
注:這裡使用了2個Controller,需要在這裡注冊下,并自動建立Viewport元件,會自動從"appFolder"參數指定的目錄中搜尋。
2、app/Viewport.js
Ext.define('AM.view.Viewport', {
extend: 'Ext.container.Viewport',
requires: [
'AM.view.Head',
'AM.view.Menu',
'AM.view.Foot',
'AM.view.Body'
],
layout: 'border',
items: [{
region: 'north',
height: 45,
xtype: 'head'
},{
region: 'west',
width: 225,
xtype: 'menu'
},{
region: 'south',
height: 25,
xtype: 'foot'
},{
region: 'center',
xtype: 'body'
}]
});
注:requires聲明必須先引入的類,其共有四個子元素,分别布局在上、下、左和中間,下面一個一個看。
3、app/Menu.js
該控件布局在左側,是項目的管理菜單。
Ext.define('AM.view.Menu', {
extend : 'Ext.panel.Panel',
alias : 'widget.menu',
requires : [ 'AM.view.menu.Tree' ],
margins : '0 0 0 5',
split : true,
collapsible : true,
header : true,
title : '管理菜單',
initComponent : function() {
this.items = [{ xtype: 'menuTree' }];
this.callParent(arguments);
}
});
注:AM.view.Menu中添加了一個子元素,其xtype是“menuTree”,實際上是一個Tree對象。稍後會有這個對象。
4、app/Head.js
布局在上方,一般用來顯示項目名稱和一些快捷導航,這裡為了友善沒有顯示這麼複雜,就顯示“加載中...”
Ext.define('AM.view.Head', {
extend : 'Ext.panel.Panel',
alias : 'widget.head',
margins : '5 5 0 5',
split : true,
header : false,
collapsible : true,
initComponent : function() {
this.html = "<div>加載中...</div>";
this.callParent(arguments);
}
});
5、app/Foot.js
顯示在最下方,一般可以用來顯示目前登入的管理者資訊,這裡為了友善,也沒有顯示。
Ext.define('AM.view.Foot', {
extend : 'Ext.panel.Panel',
alias : 'widget.foot',
margins : '5 5 5 5',
header : false,
frame : true,
collapsible : true,
initComponent : function() {
this.callParent(arguments);
}
});
6.app/Body.js
管理子產品的主體部分,根據管理的子產品不同,即時渲染相應的控件來顯示資料、修改資料、添加、删除資料等操作。這裡隻是加載了一個xtype為'userList',顯示的是使用者清單,後面會說到這個控件。
Ext.define('AM.view.Body', {
extend : 'Ext.panel.Panel',
alias : 'widget.body',
requires : [ 'AM.view.user.List' ],
margins : '0 5 0 0',
border : 0,
header : false,
baseCls : 'x-plain',
collapsible : true,
initComponent : function() {
this.items = [ {
xtype: 'userList'
} ];
this.callParent(arguments);
}
});
7、app/controller/Menu.js
這個是左側菜單的控制器,處理左側菜單的事件以及事件的處理,這裡隻是在單擊菜單時寫入了一條日志。
Ext.define('AM.controller.Menu', {
extend: 'Ext.app.Controller',
stores: ['Menu'],
views: ['menu.Tree'],
init: function() {
this.control({
'menuTree': {
itemclick: this.selectItem
}
});
},
selectItem: function(){
console.log('click item');
}
});
8、app/store/Menu.js
左側菜單的Store對象,負責處理資料。
Ext.define('AM.store.Menu', {
extend: 'Ext.data.TreeStore',
autoLoad : true,
proxy: {
type: 'ajax',
api: {
read: '/Content/Manage/data/menus.js'
},
reader: {
type: 'json',
root: 'childrens'
}
},
sorters: [{
property: 'leaf',
direction: 'ASC'
}],
root: {
nodeType: 'async',
text: 'Ext JS',
expanded: true
}
});
這裡調用的是靜态資料,頁面URL是"/Content/Manage/data/menus.js",其資料如下:
{childrens:[
{id:'01',text:'資料管理',childrens:[
{id:'01-01',text:'新聞管理',leaf:true},
{id:'01-02',text:'分類管理',leaf:true},
{id:'01-03',text:'公告管理',leaf:true}
]},
{id:'02',text:'系統配置',leaf:true}
]}
9、app/view/menu/Tree.js
左側菜單的視圖檔案,負責渲染元件:
Ext.define('AM.view.menu.Tree' ,{
extend: 'Ext.tree.Panel',
alias : 'widget.menuTree',
header : false,
border : 0,
store: 'Menu',
rootVisible: false
});
現在來看使用者的相關對象,先看控制器:
10、app/controller/User.js
Ext.define('AM.controller.User', {
extend: 'Ext.app.Controller',
stores: ['User'],
views: ['user.List'],
models: ['User']
});
由于使用者資料需要Model對象,來看下:
11、app/model/User.js
Ext.define('AM.model.User', {
extend : 'Ext.data.Model',
fields : [ 'name', 'email' ]
});
再看下Store:
12、app/store/User.js
Ext.define('AM.store.User', {
extend: 'Ext.data.Store',
model: 'AM.model.User',
autoLoad: true,
sorters: [{
property: 'code',
direction: 'ASC'
}],
proxy: {
type: 'ajax',
api: {
read: '/Content/Manage/data/userList.js'
},
reader: {
type: 'json',
root: 'users',
successProperty: 'success'
}
},
listeners:{
update: function(store, record){
console.log('listeners update. name='+record.get('name'));
}
}
});
這個Store稍微複雜些,使用了Proxy對象,複雜與背景進行資料互動。這裡不詳解,以後的文章都會一一細說。
這裡隻說/Content/Manage/data/userList.js傳回的資料:
{
success: true,
users: [
{id: 1, name: '崔北為', email: '[email protected]'},
{id: 2, name: '李軍', email: '[email protected]'},
{id: 3, name: '錢雲祿', email: '[email protected]'}
]
}
13、app/view/user/List.js
Ext.define('AM.view.user.List' ,{
extend: 'Ext.grid.Panel',
alias : 'widget.userList',
title : 'All Users',
store: 'User',
columns: [
{header: 'Name', dataIndex: 'name', flex: 1},
{header: 'Email', dataIndex: 'email', flex: 1}
],
buttons:[
{text:'add',action:'add'},
{text:'delete',action:'delete'}
]
});
到此,所有的js檔案全部搞定,可以測試運作了。
五、運作預覽