一步一步使用Ext JS MVC與Asp.Net MVC 3開發簡單的CMS後台管理系統之登入視窗

來源:互聯網
上載者:User

      完成配置後,要做的是完成登入頁面。因為要實現登入之後寫入認證資訊到Cookie,因而必須做一次跳轉。當然,不做跳轉,或不寫入認證資訊也行,但問題比較複雜,在這裡還是做簡單處理比較合適。還有就是寫入認證資訊的目的是為了在控制器通過特性控制方法的許可權。

      既然要跳轉一次,就有兩種思路了,一種是為了快速顯示登入頁,可不載入Ext JS,而是使用傳統的頁面,顯示一個登入頁,這樣頁面載入快,使用者感受也好很多。第二種方式就是用Ext JS視窗做一個登入視窗,不過要載入Ext JS庫,顯示時間會久點,體驗不是太好。不過載入過Ext JS,後面顯示主架構頁的時候就可以利用快取資料。採用那種方式,根據自己喜好或項目要求定吧。本文是示範Ext JS的,因而會採用第二種方式,寫一個登入視窗。

      登入視窗作為常用組件,在其它項目也會用到,因而很適合寫成一個擴充。這裡還要考慮一個問題,是寫成單例模式的擴充,還是單純是擴充?單例模式的好處是在頁面中直接用show方法顯示就行了,而純擴充的好處的是可以通過配置項自訂標題、表徵圖這類的東西。筆者更喜歡單例模式,原因是直接在擴充中修改標題之類的這些東西,比使用配置項來定義來得方便,畢竟是Javascript寫的擴充,修改起來比使用C#這些語言的擴充容易得多了。

      目標明確後,就可以動手了,在方案總管中選擇Scripts\ExtJS\ux目錄,單擊右鍵選擇添加,建立項,在快顯視窗中6那樣選擇Jscript檔案,並將名稱修改為login.js(以後的項目的可直接將該檔案複製到該目錄),單擊添加按鈕建立檔案。這裡要注意,檔案名稱不能用類的全名做檔案名稱,因為動態載入會根據類名自動找到目錄並負載檔案,類名中最後一個小數點後的名稱就是檔案名稱,例如,登入視窗的類全稱為Ext.ux.Login,而login就是檔案名稱。

      如果想要在指令碼中使用ExtJS的提示資訊,可將書附帶的資源套件中的Ext.js檔案複製到ExtJS目錄中,複製後,在方案總管將Ext.js拖到到login.js檔案中,就會產生以下代碼:

/// <reference path="../Ext.js" />

      這樣,就可以在指令碼中使用Ext  JS的提示資訊,在檔案中輸入“Ext.cr”,將看到7所示的效果。

      現在,先把類的定義寫好,包括父類、單例模式、視窗標題、寬度和高度。視窗的標題為“簡單的CMS後台管理系統後台登入視窗”。寬度和高度暫訂為400,到時候再調整。最終代碼如下:

Ext.define("Ext.ux.Login", {    extend: "Ext.window.Window",    singleton: true,    title: '簡單的CMS後台管理系統後台登入視窗',    width: 400,    height: 400});

       接下來,要考慮視窗應該包含那些配置項了,視窗應是模態的,不能關閉,不能調整大小,關閉模式為隱藏,隱形模式為位移等,因而加入以下代碼:

    modal: true,    closable: false,    resizable: false,    closeAction: 'hide',    hideMode: 'offsets',

      好了,現在要在視窗的initComponent方法內定義登入用的控制項了。一般的登入視窗都包含使用者名稱、密碼和驗證碼3個文本輸入框,還包含有顯示驗證碼的圖片、登入和重設按鈕。因而需要用到的ExtJS控制項包括表單面板、圖片、工具列、按鈕和文字欄位。下面要做的是先定義好表單,在擴充內加入以下代碼:

    initComponent: function () {        var me = this;        me.form = Ext.create(Ext.form.Panel, {                    });me.callParent(arguments);    }

      代碼中,me的作用是將外部範圍中的this對象儲存為本地變數,這樣的好處包括,一是,如果this是window等全域變數,就可以將全域變數變成本地變數,提高訪問效率,二是可以讓閉包訪問該對象。這寫法在Ext JS檔案中始終貫穿其中,本著拿來主義的精神,好東西應該學一下。

      注意create方法中的對象名稱,筆者並沒有使用字串,這樣就可以直接使用對象,而不需要再去轉換表中找對象,可以提高速度,筆者建議這樣寫。

      調用callParent方法是必須的,不然組件運行會出問題,達不到預期效果,具體請參考筆者書中的講解。

       接下來是定義表單的配置項了,筆者習慣的配置項有以下幾個:

border: false, bodyPadding: 5,bodyStyle: "background:#DFE9F6",

      代碼中,第一句表示不要邊框,如果喜歡帶有邊框的表單,可以把這項去掉或者修改為true。第二句表示將表單面板向內壓縮5像素,這樣表單內的組件就不會和視窗的內邊框粘在一起,這個可根據個人喜好設定。第三句的作用就是讓表單面板的背景顏色和視窗融合在一起,而不是預設的白色,這還是個人喜好問題。

      接著加入表單面板的提交地址,這裡定為Account/Login,就是Account控制器的Login方法,代碼如下:

url: "Account/Login",

      因為表單內使用的都是文字欄位,因而可以統一做一些定義,如標籤寬度為80,標籤的分隔字元為中文冒號,錨固為0,都不允許為空白等,代碼如下:

defaultType: "textfield",fieldDefaults: {    labelWidth: 80, labelSeparator: ":", anchor: "0", allowBlank: false},

      接下來是定義欄位了,這個簡單,因為預設設定已經定義了幾個配置項,因而餘下的就只有欄位標籤和名稱。驗證碼特殊點,必須是6位字元,代碼如下:

items: [{    fieldLabel: "使用者名稱", name: "UserName"},{    fieldLabel: "密碼", name: "Password", inputType: "password"},{    fieldLabel: "驗證碼", name: "Vcode", minLength: 6, minLength: 6}]

      現在要考慮怎麼顯示驗證碼圖片,如果直接在表單內加入Image控制項,會很難控製圖片的位置,因為最好的方式是先套一個容器。因為Img對象的執行個體在重新整理圖片的時候還要用到,因而最好用一個屬性來指向對象執行個體,這樣就可以通過該屬性在類的內部訪問到執行個體了。在建立表單的前面添加以下建立Img對象執行個體的代碼:

me.image=Ext.create(Ext.Img,{    src: "/VerifyCode"});

      千萬不要在建立表單後面建立,不然在表單插入入圖片的時候就找不到對象了。

      代碼中,驗證碼圖片將VerifyCode控制器產生,這個暫時放下,會在後面討論。

      還要實現的是單擊圖片重新整理驗證碼,但是查API發現Img對象居然沒單擊事件。沒關係,在4.1版本的Ext JS中,修改了事件的定義方式,可以直接為對象產生的HTML元素繫結事件了,只要在監聽事件中加入element配置項就行了,這相當方法。因而可在建立Img執行個體的設定物件中加入以下代碼:

listeners:{    click:me.onRefrehImage,    element:"el",scope:me}

       代碼中,element配置項中的el就表示要在對象產生的HTML元素中綁定事件,綁定事件為click事件,事件將調用onRefrehImage方法。方法只是簡單的重新整理圖片,因而使用Img對象的setSrc方法就可以,使用以下代碼順便完成onRefrehImage方法:

onRefrehImage: function () {    this.image.setSrc("/VerifyCode?_dc=" + (new Date()).getTime());}

      代碼很簡單,使用setSrc方法重新整理圖片的src就行了,加上時間戳記可防止顯示緩衝圖片。

       好了,可以在表單items裡加入驗證碼圖片了,代碼如下:

{    xtype: "container", height: 80, anchor: "-5", layout: "fit",    items: [me.image]}

       從代碼可以看到,使用容器的作用就是可以使用fit布局來限制圖片的尺寸,這樣布局就容易多了。

      還要加入一段提示資訊,告知使用者驗證碼不區分大小寫,且如果看不清楚驗證碼圖片,可單擊圖片重新整理驗證碼,代碼如下:

{    xtype: "container", anchor: "-5", html: "**驗證碼不區分大小寫,如果看不清楚驗證碼,可單擊圖片重新整理驗證碼。"}

      表單餘下的就是添加登入和重設按鈕了,代碼如下:

dockedItems: [{xtype: 'toolbar', dock: 'bottom', ui: 'footer', layout: { pack: "center" },items: [    { text: "登入", width: 80, disabled: true, formBind: true, handler: me.onLogin, scope: me },    { text: "重設", width: 80, handler: me.onReset, scope: me }    ]}]

      在這裡使用了dockedItems配置項,目的一是因為介紹Ext JS 4的新功能,二是因為使用這個確實挺方便。代碼中定義了一個工具列,固定位置由dock配置項決定,在這裡是底部(bottom),工具列的樣式使用了ui配置項定義的footer,也就是原來視窗的底部頁尾工具列,工具列的布局將使用置中對齊。

       登入按鈕預設為禁用的。formBind配置的作用是只有在表單內輸入符合要求時才能使用該按鈕,這個設計在Ext JS4也是新加入的,很方便,不再需要自己去寫代碼實現這個了。登入按鈕將調用onLogin方法。重設按鈕很簡單,只是簡單的調用onReset方法。

       餘下要完成的是onLogin和onReset方法。先來完成簡單onReset方法,準系統就是重設表單,並將焦點移動到第一個文字欄位,也就是使用者名稱那裡,還要重新整理驗證碼,代碼如下:

onReset: function () {    var me = this;    me.form.getForm().reset();    if (me.form.items.items[0]) {        me.form.items.items[0].focus(true, 10);    }    me.onRefrehImage();}

      代碼中要注意的是擷取表單中第一個文字欄位的代碼,因為表單在執行個體化後,items屬性指向的是MixedCollection執行個體,因為要在其items內才能找到文本自動對象。

      接著完成的是onLogin方法,難度也不大, 就是先調用isValid方法,驗證表單是否符合提交要求,然後調用submit方法提交。其實不調用isValid也行,因為登入按鈕只要在isValid為true時才能用,不過筆者習慣如何,多餘就多餘點吧。代碼如下:

onLogin: function () {    var me = this,f = me.form.getForm();    if (f.isValid()) {        f.submit({            waitMsg: "正在登入,請等待……",            waitTitle: "正在登入",            success: function (form, action) {            window.location.reload();            },            failure: function(){            },            scope: me        });    }}

      在submit方法內,waitMsg和waitTitle會顯示一個等待對話方塊,並用一個遮罩遮住表單,不讓使用者編輯,其中waitMsg就是要顯示的提示資訊,waitTitle就是快顯視窗的標題的。不過,在4.1.1版本,這裡有bug,筆者已提交至官方論壇,修正方法可參閱http://www.sencha.com/forum/showthread.php?228970-4.1.1-GA-Form-Submit-Problem。這裡筆者就不修正了,測試的時候會屏蔽這兩句代碼。

       登入成功(success配置項)後,會重新整理一下頁面,讓頁面寫入驗證資訊到Cookie。當然,也可以跳轉到另外一頁,不過筆者認為不如這樣來得簡便,這個稍後會說到。

      登入失敗(failure配置項),唯寫了一個空函數的目的是因為表單的提交返回的資料格式是一樣的,處理方式也一樣,因而可使用同一個函數進行處理,但是還沒寫到,因而先保留一個空函數。

      最後,別忘了將表單加入視窗的items裡,這個必須放在調用callParent之前,不如不會初始化表單,代碼如下:

me.items = [me.form]

      至此,登入視窗就暫時寫好了,今天的進度也完成了。

      嘿嘿,這樣的項目進度會鬱悶死專案經理的。

     懶得上傳檔案了,以下是完整的Login.js代碼:

/// <reference path="../Ext.js" />Ext.define("Ext.ux.Login", {    extend: "Ext.window.Window",    singleton: true,    title: '簡單的CMS後台管理系統後台登入視窗',    width: 400,    height: 400,    modal: true,    closable: false,    resizable: false,    closeAction: 'hide',    hideMode: 'offsets',    initComponent: function () {        var me = this;        me.image = Ext.create(Ext.Img, {            src: "/VerifyCode",            listeners: {                click: me.onRefrehImage,                element: "el",                scope: me            }        });        me.form = Ext.create(Ext.form.Panel, {            border: false,            bodyPadding: 5,            bodyStyle: "background:#DFE9F6",            url: "Account/Login",            defaultType: "textfield",            fieldDefaults: {                labelWidth: 80,                labelSeparator: ":",                anchor: "0",                allowBlank: false            },            items: [{    fieldLabel: "使用者名稱", name: "UserName"},{    fieldLabel: "密碼", name: "Password", inputType: "password"},{    fieldLabel: "驗證碼", name: "Vcode", minLength: 6, minLength: 6},{    xtype: "container", height: 80, anchor: "-5", layout: "fit",    items: [me.image]},{    xtype: "container", anchor: "-5", html: "**驗證碼不區分大小寫,如果看不清楚驗證碼,可單擊圖片重新整理驗證碼。"}],            dockedItems: [{                xtype: 'toolbar', dock: 'bottom', ui: 'footer', layout: { pack: "center" },                items: [        { text: "登入", width: 80, disabled: true, formBind: true, handler: me.onLogin, scope: me },        { text: "重設", width: 80, handler: me.onReset, scope: me }    ]            }]        });        me.items = [me.form]        me.callParent(arguments);    },    onRefrehImage: function () {        this.image.setSrc("/VerifyCode?_dc=" + (new Date()).getTime());    },    onReset: function () {        var me = this;        me.form.getForm().reset();        if (me.form.items.items[0]) {            me.form.items.items[0].focus(true, 10);        }        me.onRefrehImage();    },    onLogin: function () {        var me = this,f = me.form.getForm();        if (f.isValid()) {            f.submit({                waitMsg: "正在登入,請等待……",                waitTitle: "正在登入",                success: function (form, action) {                window.location.reload();                },                failure: function(){                },                scope: me            });        }    }});

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.