現在要考慮的是如何加載標籤頁內的內容。雖然標籤頁默認是延遲渲染的(deferredRender值默認爲true),但是它會預加載所有的類,因而當類文件很多的時候,加載時間就是一大問題了。這個,也可通過SDK打包的方式解決,不過在設計階段還是要考慮的。另一種好的解決方法是,只使用標籤頁的標籤,而不使用其主體加載內容,另外使用一個容器,內部使用CardLayout作爲佈局,類似書中最後一章的示例實現面板內容的加載和切換。
在這裏,將展示另一種方式,就是在標籤頁激活時纔去加載內容頁。因而,這需要監聽標籤頁的activate事件。這樣,問題又來了,是在標籤頁面板監聽activate事件,還是在每個獨立的標籤頁內監聽activate事件。如果是在標籤頁面板內監聽,就要判斷當前標籤頁的哪一個,是否需要加載內容,因爲文章的詳細信息頁也是標籤頁,因而這些都需要做判斷。這個,筆者因爲雖然寫法簡化了,但是要做的判斷實在太多,不算太好的方法。而在具體標籤頁內監聽,則不需要任何判斷,而且可以設置事件爲一次性性事件,也就是在監聽時設置事件的single配置項爲true,這樣監聽事件在執行一次後就會自動刪除,不再監聽了。
要在Viewport內爲各標籤頁添加activate事件,就不太符合MVC要求了。是的,這個在頂部實現退出按鈕的時候已經違反要求了。因而都需要做出修改。不過,筆者也曾思前想後的考慮過,開發應用程序,是否就要這麼刻板呢?尤其是像退出這樣簡單的操作,而且對於Javascript這樣靈活的語言。這個,如果探討起來,就和語言之爭一樣沒什麼意義了,大家還是根據自己習慣,靈活掌握吧。
爲了實現標籤頁的MVC化,先在view目錄下創建一個名稱爲MainPanel.js的文件,在文件裏定義一個擴展於標籤面板的控件,基本代碼如下:
Ext.define('SimpleCMS.view.MainPanel',{
extend : 'Ext.tab.Panel',
alias : 'widget.mainpanel',
flex : 1,
initComponent: function(){
var me = this;
me.callParent(arguments);
}
});
使用配置項alias來爲組件定義一個別名非常有必要,不然在Viewport就不能使用xtype來創建組件了,在這裏,別名是mainpanel。在initComponet方法內,將Viewport創建mainpanel實例的代碼複製過來,並修改如下:
me.items= [
{ title: "文章管理" , id :"contentPanel"},
{ title: "圖片管理" , id : "picPanel"}
];
varroles = "." + SimpleCMS.Userinfo.Roles.join('.') + ".";
if(roles.indexOf(".系統管理員.") >= 0) {
me.items.push({ title: "用戶管理",id:"userPanel"});
}
因爲是在組件內,所以將標籤頁加到items裏就行了。要注意,所有標籤頁都添加了id,其目的是爲了方便在控制器中找到面板,當然,這個使用其它方式獲取也行,只是這樣的方式是最快最直接的。這個可根據項目具體情況再做決定。還要注意,添加用戶管理標籤頁時,用的是數組的push方法,而不是面板的add方法了。
現在,在Controller目錄創建一個名稱爲MainPanel.js的腳本文件,用來定義主面板的控制,基本定義代碼如下:
Ext.define('SimpleCMS.controller.MainPanel',{
extend: 'Ext.app.Controller',
init: function () {
}
});
因爲控制器裏不需要引用組件,也不需要模型和Store,因而沒有定義refs、store和model配置項,只是定義了init方法。在init方法內,需要使用控制器的control方法來獲取主面板內的標籤頁,併爲其添加activate事件,具體代碼如下:
this.control({
'#contentPanel': {
activate: {
single: true,
fn : function (panel) {
console.log(panel);
}
}
},
'#picPanel': {
activate: {
single: true,
fn: function (panel) {
console.log(panel);
}
}
},
'#userPanel': {
activate: {
single: true,
fn: function (panel) {
console.log(panel);
}
}
}
}
代碼中,對象中的關鍵字就是選擇器,用來查找組件用的,在這裏要使用id來查找,因而在組件id前面要添加“#”符號,表示使用id查找組件。在組件內,綁定了activate事件,事件中,single配置項說明該事件只執行一次,配置項fn則是事件的回調函數,目前只是簡單的顯示返回的面板對象。
在這裏,沒有使用權限添加用戶面板的原因是,如果找不到組件,它不會做任何處理,因而不使用權限添加也沒問題的,不像可視組件內,如果不限制,就會顯示出來。在這裏,一般都會擔心,這會不會造成安全問題?被利用來實現無權限的操作,這個其實不用擔心,就算它能看到顯示的組件,但是我後臺通過權限控制返回的數據,它沒有權限,是看不到任何數據的,也不能對沒權限的數據進行任何操作。
控制器定義好以後,切換會Viewport.js,先添加一個requires配置項,讓其自動加載MainPanel,代碼如下:
requires:['SimpleCMS.view.MainPanel'],
這句是必須的,不然會找不到組件。
然後將之前添加mainpanel的代碼全部刪除,在items內原來添加主面板的位置添加以下代碼來添加主面板視圖:
{xtype: "mainpanel", id: "mainPanel" },
在這裏,也加了一個id,也是爲了方便以後使用選擇器查找組件。
因爲要加載主面板的控制器,所以要在首頁Index.cshtml使用application方法創建應用時添加controllers配置項,代碼如下:
controllers:["MainPanel"]
這樣,就可自動加載主面板的控制器了。
現在,在瀏覽器中打開首頁,使用test用戶登錄,會看到界面和之前看到的沒有區別。如果打開了Firebug,會看到以下顯示:
[試用版]Ext.panel.Panel { id="contentPanel", title="文章管理"}
這說明activate事件已被觸發了,不相信?可以在activate事件內添加別的東西來做個驗證。
單擊一下圖片管理,會看到Firebug裏又多了以下信息:
[試用版]Ext.panel.Panel { id="picPanel", title="圖片管理"}
說明圖片管理面板的activate也被觸發了。
現在再切換回文章管理,會發現不再有提示信息了,原因就是activate事件設置了配置項single爲true,它只會執行一次。
好了,Viewport到此就已經完成了。現在的重點是如何在主面板控制器內控制內容的加載了。