javascript
Ext JS 6学习文档-第3章-基础组件
Ext JS 6學(xué)習(xí)文檔-第3章-基礎(chǔ)組件
基礎(chǔ)組件
在本章中,你將學(xué)習(xí)到一些 Ext JS 基礎(chǔ)組件的使用。同時(shí)我們會(huì)結(jié)合所學(xué)創(chuàng)建一個(gè)小項(xiàng)目。這一章我們將學(xué)習(xí)以下知識(shí)點(diǎn):
- 熟悉基本的組件 – 按鈕,文本框,日期選擇器等等
- 表單字段的校驗(yàn)
- 菜單和工具欄
- 設(shè)計(jì)一個(gè)表單
- 計(jì)算器程序– 本章的示例項(xiàng)目
本章的主要目的是創(chuàng)建一個(gè)表單設(shè)計(jì)和一個(gè)計(jì)算器示例項(xiàng)目。以下圖分別展示了表單設(shè)計(jì)和計(jì)算器設(shè)計(jì)。
首先,你觀察下列表單設(shè)計(jì),你會(huì)發(fā)現(xiàn)我們使用了大量的控件,例如 label 和文本框。
以下圖展示了表單的設(shè)計(jì):
?
繼續(xù),設(shè)計(jì)計(jì)算器程序大量的使用了按鈕控件。所以你首要學(xué)習(xí)的是按鈕和 handler 。隨后在本章最后我們將會(huì)構(gòu)建一個(gè) 計(jì)算器程序。在這個(gè)過(guò)程中,你會(huì)知道如何使 view(視圖) 和 controller(控制器)進(jìn)行交互并協(xié)同工作。我們還將看到如何綁定 view model(視圖模型) 的屬性到一個(gè) view(視圖) 的字段上。
下圖為計(jì)算機(jī)的設(shè)計(jì)展示:
熟悉基本組件
Ext JS 有大量的優(yōu)秀的控件,現(xiàn)在讓我們開(kāi)始認(rèn)識(shí)這些基礎(chǔ)的組件吧。
Ext.Button
這是一個(gè)很常用的控件;handler 是用于處理單擊事件,如以下代碼所示:
| 1 2 3 4 5 6 7 | Ext.create('Ext.Button', {?? ????text: 'My Button',?? ????renderTo: Ext.getBody(),?? ????handler: function() {???? ????????alert('click'); ????} }); |
前面代碼的輸出:
?
我在第二章已經(jīng)介紹過(guò)如何運(yùn)行樣例代碼,但這里我還想再次重申這一點(diǎn),此文檔中的大部分樣例代碼都是可以直接運(yùn)行的。你可以選擇在你本地設(shè)備上或者在 Sencha Fiddle 上執(zhí)行這些示例代碼。你可以訪問(wèn)?Sencha Fiddle?并將上面的代碼鍵入到 launch 函數(shù)中,運(yùn)行并查看結(jié)果。如果你訪問(wèn)了https://fiddle.sencha.com?將會(huì)看到下列代碼:
| 1 2 3 4 5 6 | Ext.application({?? ????name : 'Fiddle',?? ????launch : function() { ????????Ext.Msg.alert('Fiddle', 'Welcome to Sencha Fiddle!'); ????} }) ; |
?
現(xiàn)在粘貼下列的創(chuàng)建按鈕的樣例代碼,運(yùn)行并查看結(jié)果:
| 1 2 3 4 5 6 7 8 9 10 11 12 | Ext.application({?? ????name : 'Fiddle',?? ????launch : function() { ????????Ext.create('Ext.Button', {?????? ????????????text: 'My Button',?????? ????????????renderTo: Ext.getBody(),?????? ????????????handler: function() {???????? ????????????????alert('click'); ????????????} ????????}); ????} }); |
?
- 不是所有的代碼都可以這樣運(yùn)行,此外并非所有的示例代碼都會(huì)有視覺(jué)呈現(xiàn)。
你還可以使用?listeners?配置添加更多的事件處理器,如以下代碼所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Ext.create('Ext.Button', {?? ????text: 'My Button',?? ????renderTo: Ext.getBody(),?? ????listeners: {???? ????????click: {?????? ????????????fn: function(){ ????????????????//Handle click event???????? ????????????????alert('click'); ????????????} ????????}, ????????mouseout: {?????? ????????????fn: function(){ ????????????????//Handle double click event???????? ????????????????alert('Mouse out'); ???????????? } ????????} ????} }); |
?
以上代碼只是創(chuàng)建了一個(gè)簡(jiǎn)單的按鈕,你還可以創(chuàng)建很多不同的按鈕,有 link button(連接按鈕),menu button(菜單按鈕),toggle button(開(kāi)關(guān)按鈕) 等等;
來(lái)創(chuàng)建一個(gè)鏈接按鈕,設(shè)置?href?屬性,如以下代碼所示:
| 1 2 3 4 5 | Ext.create('Ext.Button', {?? ????renderTo: Ext.getBody(),?? ????text: 'Link Button',?? ????href: 'http://www.sencha.com/' }); |
上面創(chuàng)建的鏈接按鈕輸出如圖。當(dāng)點(diǎn)擊它則打開(kāi)鏈接:
?
通過(guò)設(shè)置?menu?屬性,創(chuàng)建一個(gè)菜單按鈕,如以下代碼所示:
| 1 2 3 4 5 6 7 8 9 10 11 | Ext.create('Ext.Button', {?? ????text: 'My Button',?? ????renderTo: Ext.getBody(),?? ????menu: [{???? ????????text: 'Item 1' ????}, {???? ????????text: 'Item 2' ????}, {???? ????????text: 'Item 3' ????}] }); |
輸出如下,當(dāng)點(diǎn)擊時(shí)出現(xiàn)下拉菜單:
Ext.Button?還有許多屬性,例如?bind,?cls,?disabled,html,tooltip,tpl?等等,你可以根據(jù)自己需求使用。
Ext.MessageBox
Ext.window.MessageBox?類(lèi)提供了 message box 實(shí)現(xiàn)。Ext. MessageBox?是一個(gè)單例對(duì)象。你可以使用?MessageBox?彈出一個(gè)警告,信息確認(rèn),提示輸入等等。
下列代碼將彈出一個(gè)簡(jiǎn)單的提示信息。這里解釋一下?Ext.Msg?是?Ext. Messagebox?類(lèi)的別名:
| 1 | Ext.Msg.alert('Info', 'Document saved!'); |
?
下列代碼將彈出一個(gè)消息確認(rèn)框,button 為選擇的值,取 yes 或 no :
| 1 2 3 4 5 6 7 | Ext.Msg.confirm('Confirm', 'Are you want to cancel the updates?', function(button){?? ????if('yes'==button) { ????}?? else { ????} }); |
?
你也可以自定義這個(gè) message box 如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | Ext.MessageBox.show({?? ????title:'Save Changes?',?? ????msg: 'Do you want to save the file?',?? ????buttons: Ext.MessageBox.YESNO,?? ????fn: function(button){???? ????????if('yes'==button){ ????????}else if('no'==button){ ????????}?? ????}, ????icon: Ext.MessageBox.QUESTION }) ; |
?
上面代碼輸出如下:
表單和表單字段
現(xiàn)在我們看一下都有哪些表單相關(guān)的組件。
Ext.form.Panel
這個(gè) form panel (表單面板)繼承自 panel? 并添加了表單相關(guān)的功能,例如字段管理,校驗(yàn),提交等等。form panel 的默認(rèn)布局是 anchor layout ,但是如果需要你可以改變這個(gè)配置。
form panel 有一個(gè)很方便的配置為?fieldDefaults,它可以用于指定表單內(nèi)所有字段的默認(rèn)類(lèi)型。
fields (字段/表單域)
Ext JS 提供了很多內(nèi)置的表單字段。比較常用的一些字段:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Ext.form.field.Checkbox Ext.form.field.ComboBox Ext.form.field.Date Ext.form.field.File Ext.form.field.Hidden Ext.form.field.HtmlEditor Ext.form.field.Number Ext.form.field.Radio Ext.form.field.Text Ext.form.field.TextArea Ext.form.field.Time |
?
我們看一下其中的一些字段的應(yīng)用。
Ext.form.field.Text
這是一個(gè)基本的文本框,它具有很多有用的屬性和配置。其中有一個(gè)很有用的屬性是?vtype?它是用于校驗(yàn)的。 例如以下代碼,這個(gè)?vtype?屬性為 email 用于驗(yàn)證輸入內(nèi)容是否是有效的電子郵箱:
| 1 2 3 4 5 6 7 | Ext.create('Ext.form.field.Text', {?? ????renderTo: Ext.getBody(),?? ????name: 'email',?? ????fieldLabel: 'Email',?? ????allowBlank: false,?? ????vtype: 'email' }); |
這里?allowBlank?也是一個(gè)校驗(yàn)屬性。通過(guò)設(shè)置 allowBlank 屬性為 false ,如果這個(gè)字段為空白,將會(huì)提示校驗(yàn)不通過(guò)。
Ext.form.field.Number
number 字段繼承自 spinner 字段,spinner 字段則繼承自 text 字段,進(jìn)而的 number 等于是繼承了兩者。這個(gè) number 字段提供了幾個(gè)選項(xiàng)來(lái)處理數(shù)值。下列代碼創(chuàng)建了一個(gè)數(shù)值文本框:
| 1 2 3 4 5 6 7 8 | Ext.create('Ext.form.field.Number', {?? ????renderTo: Ext.getBody(),?? ????name: 'Count',?? ????fieldLabel: 'Count', ????value: 0,?? ????maxValue: 10,?? ????minValue: 0 }); |
你可以移除下拉按鈕,方向鍵,鼠標(biāo)滾輪監(jiān)聽(tīng),用配置:hideTrigger,?keyNavEnabled,和?mouseWheelEnabled?。
Ext.form.field.ComboBox
下列代碼創(chuàng)建了一個(gè)月份下拉菜單。這個(gè)?combobox?有一個(gè)配置為?store。 這個(gè)?store?是數(shù)據(jù)源,為此下拉菜單提供數(shù)據(jù)。store?是屬于 ExtJS 中數(shù)據(jù)包部分, 在接下來(lái)的章節(jié)中我們會(huì)詳細(xì)介紹的。
combobox?中另一個(gè)重要的配置是?queryMode?。這個(gè)屬性取值可以是 ‘local’ 或者 ‘remote’。如果你設(shè)置為 remote 了,那么這個(gè)數(shù)據(jù)源 store 將在運(yùn)行加載數(shù)據(jù)時(shí)發(fā)送請(qǐng)求從遠(yuǎn)程服務(wù)器獲取數(shù)據(jù):
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | var months = Ext.create('Ext.data.Store', { ????fields: ['abbr', 'name'], ????data: [{"abbr":"JAN", "name":"January"}, ????????{"abbr":"FEB", "name":"February"},?? ????????{"abbr":"MAR", "name":"March"}, ????????{"abbr":"APR", "name":"April"},?? ????????{"abbr":"MAY", "name":"May"}, ????????{"abbr":"JUN", "name":"June"},?? ????????{"abbr":"JUL", "name":"July"}, ????????{"abbr":"AUG", "name":"August"}, ????????{"abbr":"SEP", "name":"September"},?? ????????{"abbr":"OCT", "name":"October"}, ????????{"abbr":"NOV", "name":"November"}, ????????{"abbr":"DEC", "name":"December"}] }) ; Ext.create('Ext.form.ComboBox', {?? ????fieldLabel: 'Choose Month', ????store: months,?? ????queryMode: 'local',?? ????displayField: 'name', ????valueField: 'abbr',?? ????renderTo: Ext.getBody() }); |
?
以上代碼的輸出如下:
Ext.form.field.HtmlEditor
Ext JS 也有一個(gè)非常優(yōu)秀的 HTML 編輯器,它提供直接在 web 頁(yè)面上處理文字的能力,如以下代碼所示:
| 1 2 3 4 5 | Ext.create('Ext.form.HtmlEditor', {?? ????width: 800,?? ????height: 200,?? ????renderTo: Ext.getBody() }); |
?
以上代碼輸出如下:
?
表單字段的校驗(yàn)
大多數(shù)表單都有自己的校驗(yàn)規(guī)則,例如你鍵入了一個(gè)非數(shù)值的內(nèi)容到 number 字段,它將顯示一個(gè)驗(yàn)證無(wú)效的提示。再有這個(gè) text 字段(文本框) 校驗(yàn)屬性有??allowBlank,minLength,和?maxLength?。 更進(jìn)一步的,還有?regex?屬性可以使用正則表達(dá)式自定義校驗(yàn)。
form panel 的事件
form panel 支持的部分事件:
- beforeaction: 任意動(dòng)作執(zhí)行前觸發(fā),例如 submit,load,doAction 這些動(dòng)作執(zhí)行時(shí)
- actionfailed: 執(zhí)行一個(gè)動(dòng)作失敗時(shí)觸發(fā)
- actioncomplete: 在一個(gè)動(dòng)作執(zhí)行完成之后觸發(fā)This event will be fired after an action is completed
- validitychange: 表單鍵入的內(nèi)容有效性發(fā)生變化時(shí)觸發(fā)
- dirtychange: 表單的dirty狀態(tài)改變時(shí)觸發(fā)
表單字段容器
以下是一些 from panel 里很有用的容器。
Ext.form.CheckboxGroup
CheckboxGroup?繼承自?FieldContainer?用于組織復(fù)選框。下列示例中,復(fù)選框組的 items 中所有的項(xiàng)都有相同的 name ;這有助于將得到的值作為一個(gè)單一的參數(shù)傳遞給服務(wù)器。
| 1 2 3 4 5 6 7 8 9 10 | Ext.create('Ext.form.CheckboxGroup', {?? ????renderTo: Ext.getBody(),?? ????fieldLabel: 'Skills ',?? ????vertical: true,?? ????columns: 1,?? ????items: [{ boxLabel: 'C++', name: 'rb', inputValue: '1' }, ????????{ boxLabel: '.Net Framework', name: 'rb', inputValue: '2', checked: true }, ????????{ boxLabel: 'C#', name: 'rb', inputValue: '3' }, ????????{ boxLabel: 'SQL Server', name: 'rb', inputValue: '4' }] }) ; |
?
以上代碼輸出如下:
Ext.form.FieldContainer
FieldContainer?是很有用的,當(dāng)你想將一組相關(guān)字段附加到一個(gè)標(biāo)簽時(shí)。
以下代碼的輸出你會(huì)發(fā)現(xiàn)一個(gè) label 后面綁定了兩個(gè)文本框:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | Ext.create('Ext.form.FieldContainer', { ????renderTo: Ext.getBody(), ????fieldLabel: 'Name',?? ????layout: 'hbox',?? ????combineErrors: true,?? ????defaultType: 'textfield', ????defaults: {???? ????????hideLabel: 'true' ????},?? ????items: [{ ????????name: 'firstName', ????????fieldLabel: 'First Name', ????????flex: 2,???? ????????emptyText: 'First',???? ????????allowBlank: false ????}, {???? ????????name: 'lastName',???? ????????fieldLabel: 'Last Name', ????????flex: 3,???? ????????margin: '0 0 0 6',???? ????????emptyText: 'Last',???? ????????allowBlank: false ????}] }); |
?
Ext.form.RadioGroup
RadioGroup?繼承自?CheckboxGroup?用于組織單選按鈕。items 中的項(xiàng)都有相同的 name,另外這是單選的,如以下代碼所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Ext.create('Ext.form.RadioGroup', {?? ????renderTo: Ext.getBody(),?? ????fieldLabel: 'Sex ',?? ????vertical: true,?? ????columns: 1,?? ????items: [{ ????????boxLabel: 'Male', ????????name: 'rb', ????????inputValue: '1' ????},{ ????????boxLabel: 'Female', ????????name: 'rb', ????????inputValue: '2' ????}] }); |
?
代碼輸出:
提交表單
使用 form 的 submit 方法提交表單。使用?getForm?方法獲取表單并?isValid?方法進(jìn)行提交前的表單內(nèi)容校驗(yàn)。如以下代碼所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var form = this.up('form').getForm(); if (form.isValid()) {?? ????form.submit({???? ????????url: 'someurl',???? ????????success: function () { ????????}, ????????failure: function () { ????????} ????}); } else { ????Ext.Msg.alert('Error', 'Fix the errors in the form') } |
?
菜單和工具欄
對(duì)于你能想到的任何的菜單和工具欄 Ext JS 提供了最完整的支持。Ext.toolbar.Toolbar?用于構(gòu)建一個(gè)工具欄。默認(rèn)情況下任何子項(xiàng)在Ext.toolbar.Toolbar?都是按鈕,但是你可以添加任意控件進(jìn)去,例如一個(gè)文本框,一個(gè)數(shù)值框,一個(gè)圖標(biāo),一個(gè)下拉菜單等等。
規(guī)范整理你的工具欄中的項(xiàng),你可以使用 空格(Ext.toolbar.Spacer), 分隔符(Ext.toolbar. Separator),和 使控件右對(duì)齊(Ext.toolbar.Fill) 。這里也可以使用快捷方式? ‘ ‘ (空格),’-‘ 和 ‘|’ (都是分隔符,只有很小的差別),和 ‘->‘ (右對(duì)齊)。
Ext.menu.Menu?用于構(gòu)建一個(gè)菜單,items 屬性中為?Ext.menu.Item?一個(gè)個(gè)菜單項(xiàng)。
一個(gè)簡(jiǎn)單的代碼示例和以下截圖的輸出:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | Ext.create('Ext.toolbar.Toolbar', {?? ????renderTo: Ext.getBody(), ????width: 800,?? items: [{ ????????text: 'My Button' ????},{ ????????text: 'My Button',???? ????????menu: [{?????? ????????????text: 'Item 1' ????????}, { ????????????text: 'Item 2' ????????}, { ????????????text: 'Item 3' ????????}] ????},{ ????????????text: 'Menu with divider',???? ????????????tooltip: { ????????????????text: 'Tooltip info',?????? ????????????????title: 'Tip Title' ????????????},???? ????????????menu: {?????? ????????????????items: [{???????? ????????????????????text: 'Task 1', ????????????????????// handler: onItemClick ????????????????}, '-', { ????????????????????text: 'Task 2', ????????????????????// handler: onItemClick ????????????????}, { ????????????????????text: 'Task 3', ????????????????????// handler: onItemClick ????????????????}] ????????????} ?? },'->',{ ?????? xtype: 'textfield',???? ???? name: 'field1', ?????? emptyText: 'search web site' ?? },'-','Some Info',{ ?????? xtype: 'tbspacer' ?? },{???? ???? name: 'Count',???? ???? xtype: 'numberfield',???? ???? value: 0,???? ???? maxValue: 10,???? ???? minValue: 0,???? ???? width: 60 ?? }] }); |
?
設(shè)計(jì)一個(gè)(客戶(hù)反饋)表單
現(xiàn)在根據(jù)之前所學(xué),我們來(lái)設(shè)計(jì)一個(gè)表單。
我們將設(shè)計(jì)如圖所示的表單:
以下是這個(gè)表單的代碼。這里我維護(hù)著一個(gè)這個(gè)例子的完整的源碼?https://github.com/ananddayalan/extjs-by-example-customer-feedback-form
這里我們所有的組件都在?Viewport?中。 這是一個(gè)專(zhuān)用的容器,它代表瀏覽器里應(yīng)用的視圖區(qū)域。
在?Viewport?中我們?cè)O(shè)置 scrollable 選項(xiàng)將子組件設(shè)為滾動(dòng)的,使用 true 或 false 。也可以取值為 x 或 y 表示只允許水平或垂直滾動(dòng):
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | Ext.create('Ext.container.Viewport', { scrollable: true,?? items: [{???? xtype: 'container',???? layout: {?? type: 'hbox',?? align: 'center',?? pack: 'center' },???? items: [ {?????? xtype: 'form',?????? bodyPadding: 20,?????? maxWidth: 700,?????? flex: 1, title: 'Custom Feedback', items:[{ xtype: 'fieldcontainer',???????? layout: 'hbox',???????? fieldLabel: 'Name',???????? defaultType: 'textfield', defaults: {?????????? allowBlank: false,?????????? flex: 1 }, items: [{?????????? name: 'firstName',?????????? emptyText: 'First Name }, {?????????? name: 'lastName',?????????? margin: '0 0 0 5',?????????? emptyText: 'Last Name' }] },{???????? xtype: 'datefield',???????? fieldLabel: 'Date of Birth', name: 'dob',???????? maxValue: new Date() /* Prevent entering the future date.*/ }, { fieldLabel: 'Email Address',???????? name: 'email', vtype: 'email', allowBlank: false }, { fieldLabel: 'Phone Number',???????? labelWidth: 100, name: 'phone', width: 200, emptyText: 'xxx-xxx-xxxx', maskRe: /[\d\-]/,???????? regex: /^\d{3}-\d{3}-\d{4}$/, regexText: 'The format must be xxx-xxx-xxxx' },{ xtype: 'radiogroup', fieldLabel: 'How satisfied with our service?', vertical: true, columns: 1, items: [ {?????????? boxLabel: 'Very satisfied', name: 'rb',?????????? inputValue: '1' }, { boxLabel: 'Satisfied',?????????? name: 'rb', inputValue: '2' }]?????? },{ xtype: 'checkboxgroup', fieldLabel: 'Which of these words would you use to describe our products? Select all that apply', vertical: true,???????? columns: 1,???????? items: [{?????????? boxLabel: 'Reliable',?????????? name: 'ch',?????????? inputValue: '1' }] },{ xtype: 'radiogroup', fieldLabel: 'How likely is it that you would recommend this company to a friend or colleague?', vertical: false,???????? defaults: { padding: 20 }, items: [ {?????????? boxLabel: '1',?????????? name: 'recommend',?????????? inputValue: '1' }],???????? buttons: [{ text: 'Submit',?????????? handler: function () { var form = this.up('form').getForm(); if (form.isValid()) {?????????????? form.submit({???????????????? url: 'cutomer/feedback',???????????????? success: function () {},???????????????? failure: function () {} }); } else { Ext.Msg.alert('Error', 'Fix the errors in the form') } } }] }] }] }] }); |
?
在以上代碼中通過(guò)在容器級(jí)設(shè)置?defaultType?屬性,這樣我們就可以不必在容器的每個(gè)子組件里重復(fù)的指定?xtype?屬性了。這樣默認(rèn)情況下,所有子組件在沒(méi)有顯式指定?xtype?時(shí)默認(rèn)的類(lèi)型都是?textfield?。
form panel 上有一個(gè) flex 配置用于填補(bǔ)父容器的寬度,同時(shí)通過(guò)設(shè)置 maxWidth 為 700 限制 form panel 的最大寬度。
字段容器使用 hbox 布局將 first name 和 last name 文本框放在一個(gè) label 標(biāo)簽下。
?
寫(xiě)一個(gè)計(jì)算器應(yīng)用
現(xiàn)在我們結(jié)合目前所學(xué)構(gòu)建一個(gè)完整的小項(xiàng)目。這是我們將要構(gòu)建的計(jì)算器的設(shè)計(jì):
?
文件夾結(jié)構(gòu)
這是我們創(chuàng)建的計(jì)算器工程的目錄結(jié)構(gòu)。這里我不是用 sencha Cmd 生成的項(xiàng)目,只是從 Ext JS 復(fù)制了一些必須的文件到項(xiàng)目文件夾中:
完整可用的項(xiàng)目在這里:?https://github.com/ananddayalan/extjs-by-example-calculator.
App – app.js
在?app.js?文件里我們簡(jiǎn)單的創(chuàng)建了?Main?視圖,作為可移動(dòng)窗體浮動(dòng)在瀏覽器:
| 1 2 3 4 5 6 | Ext.application({?? ????name: 'Calc',?? ????launch: function () { ????????Ext.create('Calc.view.main.Main').show(); ????} }); |
?
再談 MVC 和 MVVM
第一章的時(shí)候,我們已經(jīng)介紹過(guò)?MVC?(Model View Controller) 和?MVVM?(Model View ViewModel)。 這個(gè)示例項(xiàng)目的代碼很好的展示了 視圖,控制器,和視圖模型之間的區(qū)別。
Model (模型)
這代表著數(shù)據(jù)層。model 保存的數(shù)據(jù)可以包含數(shù)據(jù)驗(yàn)證和邏輯。
View (視圖)
這一層是用戶(hù)界面。包含有 button,form,和 message box 等等組件。在我們這次寫(xiě)的計(jì)算器應(yīng)用中?main.js?就是一個(gè)很好的視圖例子。
Controller (控制器)
控制器處理 view(視圖)相關(guān)的邏輯,例如 view 的 event(事件)處理,還有任何程序相關(guān)邏輯都可以寫(xiě)在這里。
ViewController (視圖控制器) 和 Controller (控制器)
在 Ext JS 5 和 6 中,有兩種類(lèi)型的控制器:ViewController?和?Controller。 這個(gè)?ViewController?自 Ext JS 5 開(kāi)始引進(jìn)的。ViewController?是為一個(gè)指定的視圖創(chuàng)建的控制器,但是這個(gè)控制器也可以交叉其他視圖的邏輯。
ViewController?帶來(lái)了一些新的概念,例如 引用和監(jiān)聽(tīng),簡(jiǎn)化視圖與控制之間的關(guān)系。同時(shí)?View?銷(xiāo)毀時(shí)?ViewController?也會(huì)被銷(xiāo)毀,他們具有相同的生命周期,在這個(gè)例子中我們沒(méi)有使用 引用和監(jiān)聽(tīng),但是在下一個(gè)例子中我們會(huì)使用的。
- 你可以使用 listeners? 代替 handler 處理事件
?
View model
view model 封裝了 view(視圖)所需要的展示邏輯,綁定數(shù)據(jù)到 view 并且每當(dāng)數(shù)據(jù)改變時(shí)處理更新。
它有別于 model ,view model?主要是為一個(gè)指定的視圖而創(chuàng)建的。一個(gè)?model?是一個(gè)純粹的數(shù)據(jù)類(lèi)并可用于整個(gè)應(yīng)用中,但一個(gè)?view model?是起到一個(gè)?view?和?model?之間的數(shù)據(jù)粘合劑的作用。看一下?main.js?的 視圖模型綁定。
視圖 — Main.js
這里我為這個(gè)計(jì)算器應(yīng)用創(chuàng)建一個(gè)視圖為?Main?。這個(gè)視圖里包含所有的按鈕,顯示字段等等。相關(guān)的事件用 controller 的方法。這個(gè)視圖的控制器已經(jīng)使用 controller 配置指定了。
這個(gè)視圖使用 table 布局,配置為 4 列。CSS 類(lèi)使用?cls?屬性指定。
代碼里有附加的注釋:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | Ext.define('Calc.view.main.Main', {?? extend: 'Ext.window.Window', /* 表示在當(dāng)前視圖加載之前先加載這些所需的類(lèi)*/ requires: [ 'Calc.view.main.MainController', ????????????'Calc.view.main.MainModel'],?? xtype: 'app-main',?? controller: 'main', /* 視圖的 view model (視圖模型)*/?? viewModel: { type: 'main' }, resizable: false,?? layout: {???? type: 'table',???? columns: 4 },?? /* defaultType 和 defaults 屬性是用于 items 內(nèi)的子組件的,任何子組件都可以覆蓋這些配置 */ defaultType: 'button',?? defaults: {???? width: 50, height: 50,???? cls: 'btn',???? handler: 'onClickNumber' },?? /* 這里我用 Ext.window.Window 的 header 顯示計(jì)算器的結(jié)果。使用 header 你可以在瀏覽器里移動(dòng)這個(gè)計(jì)算器。*/ header: {???? items: [{ xtype: 'displayfield',?????? colspan: 4,?????? width: 200,?????? cls: 'display',?????? bind: { value: '{display}' }, height: 60,?????? padding: 0 }] }, items: [{???? text: 'C',???? colspan: 2,???? width: 100,???? cls: 'btn-green',???? handler: 'onClickClear' }, {???? text: '+/-',???? cls: 'btn-green',???? handler: 'onClickChangeSign' }, {???? text: '÷',???? cls: 'btn-orange',???? handler: 'onClickOp' },{ text: '7' },{ text: '8' },{ text: '9' },{ text: '×',???? cls: 'btn-orange',???? handler: 'onClickOp' },{ text: '4' },{ text: '5' },{ text: '6' },{ text: '-',???? cls: 'btn-orange',???? handler: 'onClickOp' },{ text: '1' },{ text: '2' },{ text: '3' },{ text: '+',???? cls: 'btn-orange',???? handler: 'onClickOp' },{ text: '0',???? width: 100,???? colspan: 2 },{ text: '.',???? handler: 'onClickDot' },{ text: '=',???? cls: 'btn-orange',???? handler: 'onClickOp' }] }); |
?
控制器 — MainController.js
雖然這個(gè)控制器的代碼有點(diǎn)長(zhǎng),這是一個(gè)非常簡(jiǎn)單的代碼。控制器中有很多方法處理按鈕的點(diǎn)擊事件,例如運(yùn)算符和操作數(shù)的點(diǎn)擊處理。控制器使用了一個(gè) model 為?Main?:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | Ext.define('Calc.view.main.MainController', { extend: 'Ext.app.ViewController', alias: 'controller.main',?? views: ['Calc.view.main.Main'], models: ['Main'], //這個(gè) state 是一個(gè)自定義屬性,用來(lái)跟蹤計(jì)算器的狀態(tài)。 ????????state: { ????????????operatorClicked: false,???? ????????????selectedOperator: null,???? ????????????dotClicked: false, ????????????op1: 0,???? ????????????numberClicked: false,???? ????????????sign: true,???? ????????????decimal: false ????????}, onClickClear: function () { var vm = this.getViewModel();???? vm.set('display','0');???? this.state.selectedOperator=null; this.state.op1=0;???? this.state.isPositive = true;???? this.state.decimal = false;???? this.state.sign = true; }, onClickChangeSign: function (btn) { var vm = this.getViewModel();???? var cur = vm.get('display');???? if(cur!='0') {?????? if(this.state.sign===true ) {???????? vm.set('display', '-' + cur); }else { vm.set('display', cur.toString().substring(1)); } ?? } ?? this.state.sign=!this.state.sign; }, onClickOp: function (btn) { if(this.state.selectedOperator!=null && this.state.numberClicked===true){ var vm = this.getViewModel();?????? var op2 = parseFloat(vm.get('display'));?????? var op1 = parseFloat(this.state.op1); var result = 0; switch(this.state.selectedOperator){???????? case '+':???????? result = op1 + op2;???????? break;???????????????? case '-':???????? result = op1 - op2; break;???????????????? case '×':???????? result = op1 * op2;???????? break;???????????????? case '÷':???????? result = op1 / op2;???????? break; } vm.set('display', Math.round(result * 100) / 100); this.state.selectedOperator=null; }???? if(btn.text!='=') { this.state.operatorClicked = true; } this.state.selectedOperator = btn.text;???? this.state.numberClicked = false; }, onClickDot: function (btn) {???? if(this.state.decimal===false) {?????? var vm = this.getViewModel();?????? vm.set('display', vm.get('display') + '.'); } }, onClickNumber: function (btn) { this.state.numberClicked = true;???? if(this.state.selectedOperator ==='='){ this.onClickClear(); } var vm = this.getViewModel();???? if(this.state.operatorClicked===true) {?????? this.state.op1= vm.get('display');?????? vm.set('display', btn.text);?????? this.state.operatorClicked=false; }else{ var cur = vm.get('display');?????? if(cur == '0') {???????? cur = ''; } vm.set('display', cur + btn.text); }?? } }); |
?
?
視圖模型 — MainViewModel.js
這個(gè)?ViewModel?只有一個(gè)屬性為?display?。這個(gè)用來(lái)綁定到計(jì)算器顯示的值上。這里我們不會(huì)分別用一組字段創(chuàng)建模型,此外我們還將會(huì)硬編碼數(shù)據(jù)。
| 1 2 3 4 5 6 7 | Ext.define('Calc.view.main.MainModel', {?? ????extend: 'Ext.app.ViewModel',?? ????alias: 'viewmodel.main',?? ????data: {???? ????????display: 0.0 ????} }); |
?
在即將到來(lái)的章節(jié)中你將學(xué)習(xí)更多關(guān)于 模型,視圖模型,字段,字段類(lèi)型,校驗(yàn) 等等。
總結(jié)
在本章中,你了解了不同的基本組件,例如 文本框,數(shù)字框,按鈕,菜單等等。你已經(jīng)學(xué)會(huì)如何使用表單字段設(shè)計(jì)一個(gè)表單和我們之前創(chuàng)建了一個(gè)簡(jiǎn)單的計(jì)算器項(xiàng)目。
轉(zhuǎn)載于:https://www.cnblogs.com/hq2008/p/5804629.html
總結(jié)
以上是生活随笔為你收集整理的Ext JS 6学习文档-第3章-基础组件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【有美女看】提升用户体验,你不得不知道的
- 下一篇: react 不能往组件中传入属性的值为