1. 程式人生 > >[Ext JS 6 By Example 翻譯] 第3章 - 基礎元件

[Ext JS 6 By Example 翻譯] 第3章 - 基礎元件

轉載自:http://www.jeeboot.com/archives/1219.html

 

 

在本章中,你將學習到一些 Ext JS 基礎元件的使用。同時我們會結合所學建立一個小專案。這一章我們將學習以下知識點:

  • 熟悉基本的元件 – 按鈕,文字框,日期選擇器等等
  • 表單欄位的校驗
  • 選單和工具欄
  • 設計一個表單
  • 計算器程式– 本章的示例專案

本章的主要目的是建立一個表單設計和一個計算器示例專案。以下圖分別展示了表單設計和計算器設計。

首先,你觀察下列表單設計,你會發現我們使用了大量的控制元件,例如 label 和文字框。

以下圖展示了表單的設計:

 

繼續,設計計算器程式大量的使用了按鈕控制元件。所以你首要學習的是按鈕和 handler 。隨後在本章最後我們將會構建一個 計算器程式。在這個過程中,你會知道如何使 view(檢視) 和 controller(控制器)進行互動並協同工作。我們還將看到如何繫結 view model(檢視模型) 的屬性到一個 view(檢視) 的欄位上。

下圖為計算機的設計展示:

熟悉基本元件

Ext JS 有大量的優秀的控制元件,現在讓我們開始認識這些基礎的元件吧。

Ext.Button

這是一個很常用的控制元件;handler 是用於處理單擊事件,如以下程式碼所示:

 

 
  1. Ext.create('Ext.Button', {

  2. text: 'My Button',

  3. renderTo: Ext.getBody(),

  4. handler: function() {

  5. alert('click');

  6. }

  7. });


前面程式碼的輸出:

 

 

我在第二章已經介紹過如何執行樣例程式碼,但這裡我還想再次重申這一點,此文件中的大部分樣例程式碼都是可以直接執行的。你可以選擇在你本地裝置上或者在 Sencha Fiddle 上執行這些示例程式碼。你可以訪問Sencha Fiddle

 並將上面的程式碼鍵入到 launch 函式中,執行並檢視結果。如果你訪問了 https://fiddle.sencha.com 將會看到下列程式碼:

 

 
  1. Ext.application({

  2. name : 'Fiddle',

  3. launch : function() {

  4. Ext.Msg.alert('Fiddle', 'Welcome to Sencha Fiddle!');

  5. }

  6. }) ;


 

 

現在貼上下列的建立按鈕的樣例程式碼,執行並檢視結果:

 

 
  1. Ext.application({

  2. name : 'Fiddle',

  3. launch : function() {

  4. Ext.create('Ext.Button', {

  5. text: 'My Button',

  6. renderTo: Ext.getBody(),

  7. handler: function() {

  8. alert('click');

  9. }

  10. });

  11. }

  12. });


 

 

  • 不是所有的程式碼都可以這樣執行,此外並非所有的示例程式碼都會有視覺呈現。

你還可以使用 listeners 配置新增更多的事件處理器,如以下程式碼所示:

 

 
  1. Ext.create('Ext.Button', {

  2. text: 'My Button',

  3. renderTo: Ext.getBody(),

  4. listeners: {

  5. click: {

  6. fn: function(){

  7. //Handle click event

  8. alert('click');

  9. }

  10. },

  11. mouseout: {

  12. fn: function(){

  13. //Handle double click event

  14. alert('Mouse out');

  15. }

  16. }

  17. }

  18. });


 

 

以上程式碼只是建立了一個簡單的按鈕,你還可以建立很多不同的按鈕,有 link button(連線按鈕),menu button(選單按鈕),toggle button(開關按鈕) 等等;

來建立一個連結按鈕,設定 href 屬性,如以下程式碼所示:

 

 
  1. Ext.create('Ext.Button', {

  2. renderTo: Ext.getBody(),

  3. text: 'Link Button',

  4. href: 'http://www.sencha.com/'

  5. });


上面建立的連結按鈕輸出如圖。當點選它則開啟連結:

 

 

通過設定 menu 屬性,建立一個選單按鈕,如以下程式碼所示:

 

 
  1. Ext.create('Ext.Button', {

  2. text: 'My Button',

  3. renderTo: Ext.getBody(),

  4. menu: [{

  5. text: 'Item 1'

  6. }, {

  7. text: 'Item 2'

  8. }, {

  9. text: 'Item 3'

  10. }]

  11. });

 

輸出如下,當點選時出現下拉選單:

 

Ext.Button 還有許多屬性,例如 bind, cls, disabled,html,tooltip,tpl 等等,你可以根據自己需求使用。

 

Ext.MessageBox

Ext.window.MessageBox 類提供了 message box 實現。Ext. MessageBox 是一個單例物件。你可以使用 MessageBox 彈出一個警告,資訊確認,提示輸入等等。

下列程式碼將彈出一個簡單的提示資訊。這裡解釋一下 Ext.Msg 是 Ext. Messagebox 類的別名:

 

Ext.Msg.alert('Info', 'Document saved!');


 

 

下列程式碼將彈出一個訊息確認框,button 為選擇的值,取 yes 或 no :

 

 
  1. Ext.Msg.confirm('Confirm', 'Are you want to cancel the updates?', function(button){

  2. if('yes'==button) {

  3.  
  4. } else {

  5.  
  6. }

  7. });


 

 

你也可以自定義這個 message box 如下:

 

 
  1. Ext.MessageBox.show({

  2. title:'Save Changes?',

  3. msg: 'Do you want to save the file?',

  4. buttons: Ext.MessageBox.YESNO,

  5. fn: function(button){

  6. if('yes'==button){

  7.  
  8. }else if('no'==button){

  9.  
  10. }

  11. },

  12. icon: Ext.MessageBox.QUESTION

  13. }) ;

 

 

上面程式碼輸出如下:

表單和表單欄位

現在我們看一下都有哪些表單相關的元件。

 

Ext.form.Panel

這個 form panel (表單面板)繼承自 panel  並添加了表單相關的功能,例如欄位管理,校驗,提交等等。form panel 的預設佈局是 anchor layout ,但是如果需要你可以改變這個配置。

form panel 有一個很方便的配置為 fieldDefaults,它可以用於指定表單內所有欄位的預設型別。

 

fields (欄位/表單域)

Ext JS 提供了很多內建的表單欄位。比較常用的一些欄位:

 

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


 

 

我們看一下其中的一些欄位的應用。

 

Ext.form.field.Text

這是一個基本的文字框,它具有很多有用的屬性和配置。其中有一個很有用的屬性是 vtype 它是用於校驗的。 例如以下程式碼,這個 vtype 屬性為 email 用於驗證輸入內容是否是有效的電子郵箱:

 

 
  1. Ext.create('Ext.form.field.Text', {

  2. renderTo: Ext.getBody(),

  3. name: 'email',

  4. fieldLabel: 'Email',

  5. allowBlank: false,

  6. vtype: 'email'

  7. });


這裡 allowBlank 也是一個校驗屬性。通過設定 allowBlank 屬性為 false ,如果這個欄位為空白,將會提示校驗不通過。

 

 

Ext.form.field.Number

number 欄位繼承自 spinner 欄位,spinner 欄位則繼承自 text 欄位,進而的 number 等於是繼承了兩者。這個 number 欄位提供了幾個選項來處理數值。下列程式碼建立了一個數值文字框:

 

 
  1. Ext.create('Ext.form.field.Number', {

  2. renderTo: Ext.getBody(),

  3. name: 'Count',

  4. fieldLabel: 'Count',

  5. value: 0,

  6. maxValue: 10,

  7. minValue: 0

  8. });

 

你可以移除下拉按鈕,方向鍵,滑鼠滾輪監聽,用配置:hideTrigger, keyNavEnabled,和 mouseWheelEnabled 。

 

Ext.form.field.ComboBox

下列程式碼建立了一個月份下拉選單。這個 combobox 有一個配置為 store。 這個 store 是資料來源,為此下拉選單提供資料。store 是屬於 ExtJS 中資料包部分, 在接下來的章節中我們會詳細介紹的。

combobox 中另一個重要的配置是 queryMode 。這個屬性取值可以是 ‘local’ 或者 ‘remote’。如果你設定為 remote 了,那麼這個資料來源 store 將在執行載入資料時傳送請求從遠端伺服器獲取資料:

 

 
  1. var months = Ext.create('Ext.data.Store', {

  2. fields: ['abbr', 'name'],

  3. data: [{"abbr":"JAN", "name":"January"},

  4. {"abbr":"FEB", "name":"February"},

  5. {"abbr":"MAR", "name":"March"},

  6. {"abbr":"APR", "name":"April"},

  7. {"abbr":"MAY", "name":"May"},

  8. {"abbr":"JUN", "name":"June"},

  9. {"abbr":"JUL", "name":"July"},

  10. {"abbr":"AUG", "name":"August"},

  11. {"abbr":"SEP", "name":"September"},

  12. {"abbr":"OCT", "name":"October"},

  13. {"abbr":"NOV", "name":"November"},

  14. {"abbr":"DEC", "name":"December"}]

  15. }) ;

  16.  
  17. Ext.create('Ext.form.ComboBox', {

  18. fieldLabel: 'Choose Month',

  19. store: months,

  20. queryMode: 'local',

  21. displayField: 'name',

  22. valueField: 'abbr',

  23. renderTo: Ext.getBody()

  24. });


 

 

以上程式碼的輸出如下:

 

Ext.form.field.HtmlEditor

Ext JS 也有一個非常優秀的 HTML 編輯器,它提供直接在 web 頁面上處理文字的能力,如以下程式碼所示:

 

 
  1. Ext.create('Ext.form.HtmlEditor', {

  2. width: 800,

  3. height: 200,

  4. renderTo: Ext.getBody()

  5. });

 

 

以上程式碼輸出如下:

 

表單欄位的校驗

大多數表單都有自己的校驗規則,例如你鍵入了一個非數值的內容到 number 欄位,它將顯示一個驗證無效的提示。再有這個 text 欄位(文字框) 校驗屬性有  allowBlank,minLength,和 maxLength 。 更進一步的,還有 regex 屬性可以使用正則表示式自定義校驗。

form panel 的事件

form panel 支援的部分事件:

  • beforeaction: 任意動作執行前觸發,例如 submit,load,doAction 這些動作執行時
  • actionfailed: 執行一個動作失敗時觸發
  • actioncomplete: 在一個動作執行完成之後觸發This event will be fired after an action is completed
  • validitychange: 表單鍵入的內容有效性發生變化時觸發
  • dirtychange: 表單的dirty狀態改變時觸發

表單欄位容器

以下是一些 from panel 裡很有用的容器。

 

Ext.form.CheckboxGroup

CheckboxGroup 繼承自 FieldContainer 用於組織複選框。下列示例中,複選框組的 items 中所有的項都有相同的 name ;這有助於將得到的值作為一個單一的引數傳遞給伺服器。

 

 
  1. Ext.create('Ext.form.CheckboxGroup', {

  2. renderTo: Ext.getBody(),

  3. fieldLabel: 'Skills ',

  4. vertical: true,

  5. columns: 1,

  6. items: [{ boxLabel: 'C++', name: 'rb', inputValue: '1' },

  7. { boxLabel: '.Net Framework', name: 'rb', inputValue: '2', checked: true },

  8. { boxLabel: 'C#', name: 'rb', inputValue: '3' },

  9. { boxLabel: 'SQL Server', name: 'rb', inputValue: '4' }]

  10. }) ;

 

 

以上程式碼輸出如下:

 

Ext.form.FieldContainer

FieldContainer 是很有用的,當你想將一組相關欄位附加到一個標籤時。

以下程式碼的輸出你會發現一個 label 後面綁定了兩個文字框:

 

 
  1. Ext.create('Ext.form.FieldContainer', {

  2. renderTo: Ext.getBody(),

  3. fieldLabel: 'Name',

  4. layout: 'hbox',

  5. combineErrors: true,

  6. defaultType: 'textfield',

  7. defaults: {

  8. hideLabel: 'true'

  9. },

  10. items: [{

  11. name: 'firstName',

  12. fieldLabel: 'First Name',

  13. flex: 2,

  14. emptyText: 'First',

  15. allowBlank: false

  16. }, {

  17. name: 'lastName',

  18. fieldLabel: 'Last Name',

  19. flex: 3,

  20. margin: '0 0 0 6',

  21. emptyText: 'Last',

  22. allowBlank: false

  23. }]

  24. });

 

 

Ext.form.RadioGroup

RadioGroup 繼承自 CheckboxGroup 用於組織單選按鈕。items 中的項都有相同的 name,另外這是單選的,如以下程式碼所示:

 

 
  1. Ext.create('Ext.form.RadioGroup', {

  2. renderTo: Ext.getBody(),

  3. fieldLabel: 'Sex ',

  4. vertical: true,

  5. columns: 1,

  6. items: [{

  7. boxLabel: 'Male',

  8. name: 'rb',

  9. inputValue: '1'

  10. },{

  11. boxLabel: 'Female',

  12. name: 'rb',

  13. inputValue: '2'

  14. }]

  15. });

 

 

程式碼輸出:

提交表單

使用 form 的 submit 方法提交表單。使用 getForm 方法獲取表單並 isValid 方法進行提交前的表單內容校驗。如以下程式碼所示:

 

 
  1. var form = this.up('form').getForm();

  2. if (form.isValid()) {

  3. form.submit({

  4. url: 'someurl',

  5. success: function () {

  6.  
  7. },

  8. failure: function () {

  9.  
  10. }

  11. });

  12. } else {

  13. Ext.Msg.alert('Error', 'Fix the errors in the form')

  14. }


 

 

選單和工具欄

對於你能想到的任何的選單和工具欄 Ext JS 提供了最完整的支援。Ext.toolbar.Toolbar 用於構建一個工具欄。預設情況下任何子項在 Ext.toolbar.Toolbar 都是按鈕,但是你可以新增任意控制元件進去,例如一個文字框,一個數值框,一個圖示,一個下拉選單等等。

規範整理你的工具欄中的項,你可以使用 空格(Ext.toolbar.Spacer), 分隔符(Ext.toolbar. Separator),和 使控制元件右對齊(Ext.toolbar.Fill) 。這裡也可以使用快捷方式  ‘ ‘ (空格),’-‘ 和 ‘|’ (都是分隔符,只有很小的差別),和 ‘->‘ (右對齊)。

Ext.menu.Menu 用於構建一個選單,items 屬性中為 Ext.menu.Item 一個個選單項。

一個簡單的程式碼示例和以下截圖的輸出:

 

 
  1. Ext.create('Ext.toolbar.Toolbar', {

  2. renderTo: Ext.getBody(),

  3. width: 800, items: [{

  4. text: 'My Button'

  5. },{

  6. text: 'My Button',

  7. menu: [{

  8. text: 'Item 1'

  9. }, {

  10. text: 'Item 2'

  11. }, {

  12. text: 'Item 3'

  13. }]

  14. },{

  15. text: 'Menu with divider',

  16. tooltip: {

  17. text: 'Tooltip info',

  18. title: 'Tip Title'

  19. },

  20. menu: {

  21. items: [{

  22. text: 'Task 1',

  23. // handler: onItemClick

  24. }, '-', {

  25. text: 'Task 2',

  26. // handler: onItemClick

  27. }, {

  28. text: 'Task 3',

  29. // handler: onItemClick

  30. }]

  31. }

  32. },'->',{

  33. xtype: 'textfield',

  34. name: 'field1',

  35. emptyText: 'search web site'

  36. },'-','Some Info',{

  37. xtype: 'tbspacer'

  38. },{

  39. name: 'Count',

  40. xtype: 'numberfield',

  41. value: 0,

  42. maxValue: 10,

  43. minValue: 0,

  44. width: 60

  45. }]

  46. });

 

 

 

設計一個(客戶反饋)表單

現在根據之前所學,我們來設計一個表單。

我們將設計如圖所示的表單:

以下是這個表單的程式碼。這裡我維護著一個這個例子的完整的原始碼 https://github.com/ananddayalan/extjs-by-example-customer-feedback-form

這裡我們所有的元件都在 Viewport 中。 這是一個專用的容器,它代表瀏覽器裡應用的檢視區域。

在 Viewport 中我們設定 scrollable 選項將子元件設為滾動的,使用 true 或 false 。也可以取值為 x 或 y 表示只允許水平或垂直滾動:

 

 
  1. Ext.create('Ext.container.Viewport', {

  2. scrollable: true,

  3. items: [{

  4. xtype: 'container',

  5. layout: {

  6. type: 'hbox',

  7. align: 'center',

  8. pack: 'center'

  9. },

  10. items: [ {

  11. xtype: 'form',

  12. bodyPadding: 20,

  13. maxWidth: 700,

  14. flex: 1,

  15. title: 'Custom Feedback',

  16. items:[{

  17. xtype: 'fieldcontainer',

  18. layout: 'hbox',

  19. fieldLabel: 'Name',

  20. defaultType: 'textfield',

  21. defaults: {

  22. allowBlank: false,

  23. flex: 1

  24. },

  25. items: [{

  26. name: 'firstName',

  27. emptyText: 'First Name

  28. }, {

  29. name: 'lastName',

  30. margin: '0 0 0 5',

  31. emptyText: 'Last Name'

  32. }]

  33. },{

  34. xtype: 'datefield',

  35. fieldLabel: 'Date of Birth',

  36. name: 'dob',

  37. maxValue: new Date() /* Prevent entering the future date.*/

  38. }, {

  39. fieldLabel: 'Email Address',

  40. name: 'email',

  41. vtype: 'email',

  42. allowBlank: false

  43. }, {

  44. fieldLabel: 'Phone Number',

  45. labelWidth: 100,

  46. name: 'phone',

  47. width: 200,

  48. emptyText: 'xxx-xxx-xxxx',

  49. maskRe: /[\d\-]/,

  50. regex: /^\d{3}-\d{3}-\d{4}$/,

  51. regexText: 'The format must be xxx-xxx-xxxx'

  52. },{

  53. xtype: 'radiogroup',

  54. fieldLabel: 'How satisfied with our service?',

  55. vertical: true,

  56. columns: 1,

  57. items: [ {

  58. boxLabel: 'Very satisfied',

  59. name: 'rb',

  60. inputValue: '1'

  61. }, {

  62. boxLabel: 'Satisfied',

  63. name: 'rb', inputValue: '2'

  64. }]

  65. },{

  66. xtype: 'checkboxgroup',

  67. fieldLabel: 'Which of these words would you use to describe our products? Select all that apply',

  68. vertical: true,

  69. columns: 1,

  70. items: [{

  71. boxLabel: 'Reliable',

  72. name: 'ch',

  73. inputValue: '1'

  74. }]

  75. },{

  76. xtype: 'radiogroup',

  77. fieldLabel: 'How likely is it that you would recommend this company to a friend or colleague?',

  78. vertical: false,

  79. defaults: { padding: 20 },

  80. items: [ {

  81. boxLabel: '1',

  82. name: 'recommend',

  83. inputValue: '1'

  84. }],

  85. buttons: [{

  86. text: 'Submit',

  87. handler: function () {

  88. var form = this.up('form').getForm();

  89. if (form.isValid()) {

  90. form.submit({

  91. url: 'cutomer/feedback',

  92. success: function () {},

  93. failure: function () {}

  94. });

  95. } else {

  96. Ext.Msg.alert('Error', 'Fix the errors in the form')

  97. }

  98. }

  99. }]

  100. }]

  101. }]

  102. }]

  103. });


 

 

在以上程式碼中通過在容器級設定 defaultType 屬性,這樣我們就可以不必在容器的每個子元件裡重複的指定 xtype 屬性了。這樣預設情況下,所有子元件在沒有顯式指定 xtype 時預設的型別都是 textfield 。

form panel 上有一個 flex 配置用於填補父容器的寬度,同時通過設定 maxWidth 為 700 限制 form panel 的最大寬度。

欄位容器使用 hbox 佈局將 first name 和 last name 文字框放在一個 label 標籤下。

 

寫一個計算器應用

現在我們結合目前所學構建一個完整的小專案。這是我們將要構建的計算器的設計:

 

資料夾結構

這是我們建立的計算器工程的目錄結構。這裡我不是用 sencha Cmd 生成的專案,只是從 Ext JS 複製了一些必須的檔案到專案資料夾中:

完整可用的專案在這裡: https://github.com/ananddayalan/extjs-by-example-calculator.

 

App – app.js

在 app.js 檔案裡我們簡單的建立了 Main 檢視,作為可移動窗體浮動在瀏覽器:

 

 
  1. Ext.application({

  2. name: 'Calc',

  3. launch: function () {

  4. Ext.create('Calc.view.main.Main').show();

  5. }

  6. });


 

 

再談 MVC 和 MVVM

第一章的時候,我們已經介紹過 MVC (Model View Controller) 和 MVVM (Model View ViewModel)。 這個示例專案的程式碼很好的展示了 檢視,控制器,和檢視模型之間的區別。

Model (模型)

這代表著資料層。model 儲存的資料可以包含資料驗證和邏輯。

 

View (檢視)

這一層是使用者介面。包含有 button,form,和 message box 等等元件。在我們這次寫的計算器應用中 main.js 就是一個很好的檢視例子。

 

Controller (控制器)

控制器處理 view(檢視)相關的邏輯,例如 view 的 event(事件)處理,還有任何程式相關邏輯都可以寫在這裡。

 

ViewController (檢視控制器) 和 Controller (控制器)

在 Ext JS 5 和 6 中,有兩種型別的控制器:ViewController 和 Controller。 這個 ViewController 自 Ext JS 5 開始引進的。ViewController 是為一個指定的檢視建立的控制器,但是這個控制器也可以交叉其他檢視的邏輯。

ViewController 帶來了一些新的概念,例如 引用和監聽,簡化檢視與控制之間的關係。同時 View 銷燬時 ViewController 也會被銷燬,他們具有相同的生命週期,在這個例子中我們沒有使用 引用和監聽,但是在下一個例子中我們會使用的。

  • 你可以使用 listeners  代替 handler 處理事件

 

View model

view model 封裝了 view(檢視)所需要的展示邏輯,繫結資料到 view 並且每當資料改變時處理更新。

它有別於 model ,view model 主要是為一個指定的檢視而建立的。一個 model 是一個純粹的資料類並可用於整個應用中,但一個 view model 是起到一個 view 和 model 之間的資料粘合劑的作用。看一下main.js 的 檢視模型繫結。

 

檢視 — Main.js

這裡我為這個計算器應用建立一個檢視為 Main 。這個視圖裡包含所有的按鈕,顯示欄位等等。相關的事件用 controller 的方法。這個檢視的控制器已經使用 controller 配置指定了。

這個檢視使用 table 佈局,配置為 4 列。CSS 類使用 cls 屬性指定。

程式碼裡有附加的註釋:

 

 
  1. Ext.define('Calc.view.main.Main', {

  2. extend: 'Ext.window.Window',

  3. /* 表示在當前檢視載入之前先載入這些所需的類*/

  4. requires: [ 'Calc.view.main.MainController',

  5. 'Calc.view.main.MainModel'],

  6. xtype: 'app-main',

  7. controller: 'main',

  8. /* 檢視的 view model (檢視模型)*/

  9. viewModel: { type: 'main' },

  10. resizable: false,

  11. layout: {

  12. type: 'table',

  13. columns: 4

  14. },

  15. /* defaultType 和 defaults 屬性是用於 items 內的子元件的,任何子元件都可以覆蓋這些配置 */

  16. defaultType: 'button',

  17. defaults: {

  18. width: 50,

  19. height: 50,

  20. cls: 'btn',

  21. handler: 'onClickNumber'

  22. },

  23. /* 這裡我用 Ext.window.Window 的 header 顯示計算器的結果。使用 header 你可以在瀏覽器裡移動這個計算器。*/

  24. header: {

  25. items: [{

  26. xtype: 'displayfield',

  27. colspan: 4,

  28. width: 200,

  29. cls: 'display',

  30. bind: {

  31. value: '{display}'

  32. },

  33. height: 60,

  34. padding: 0

  35. }]

  36. },

  37. items: [{

  38. text: 'C',

  39. colspan: 2,

  40. width: 100,

  41. cls: 'btn-green',

  42. handler: 'onClickClear'

  43. }, {

  44. text: '+/-',

  45. cls: 'btn-green',

  46. handler: 'onClickChangeSign'

  47. }, {

  48. text: '÷',

  49. cls: 'btn-orange',

  50. handler: 'onClickOp'

  51. },{

  52. text: '7'

  53. },{

  54. text: '8'

  55. },{

  56. text: '9'

  57. },{

  58. text: '×',

  59. cls: 'btn-orange',

  60. handler: 'onClickOp'

  61. },{

  62. text: '4'

  63. },{

  64. text: '5'

  65. },{

  66. text: '6'

  67. },{

  68. text: '-',

  69. cls: 'btn-orange',

  70. handler: 'onClickOp'

  71. },{

  72. text: '1'

  73. },{

  74. text: '2'

  75. },{

  76. text: '3'

  77. },{

  78. text: '+',

  79. cls: 'btn-orange',

  80. handler: 'onClickOp'

  81. },{

  82. text: '0',

  83. width: 100,

  84. colspan: 2

  85. },{

  86. text: '.',

  87. handler: 'onClickDot'

  88. },{

  89. text: '=',

  90. cls: 'btn-orange',

  91. handler: 'onClickOp'

  92. }]

  93. });


 

 

控制器 — MainController.js

雖然這個控制器的程式碼有點長,這是一個非常簡單的程式碼。控制器中有很多方法處理按鈕的點選事件,例如運算子和運算元的點選處理。控制器使用了一個 model 為 Main :

 

 
  1. Ext.define('Calc.view.main.MainController', {

  2. extend: 'Ext.app.ViewController',

  3. alias: 'controller.main',

  4. views: ['Calc.view.main.Main'],

  5. models: ['Main'],

  6. //這個 state 是一個自定義屬性,用來跟蹤計算器的狀態。

  7. state: {

  8. operatorClicked: false,

  9. selectedOperator: null,

  10. dotClicked: false,

  11. op1: 0,

  12. numberClicked: false,

  13. sign: true,

  14. decimal: false

  15. },

  16. onClickClear: function () {

  17. var vm = this.getViewModel();

  18. vm.set('display','0');

  19. this.state.selectedOperator=null;

  20. this.state.op1=0;

  21. this.state.isPositive = true;

  22. this.state.decimal = false;

  23. this.state.sign = true;

  24. },

  25. onClickChangeSign: function (btn) {

  26. var vm = this.getViewModel();

  27. var cur = vm.get('display');

  28. if(cur!='0') {

  29. if(this.state.sign===true ) {

  30. vm.set('display', '-' + cur);

  31. }else {

  32. vm.set('display', cur.toString().substring(1));

  33. }

  34. }

  35. this.state.sign=!this.state.sign;

  36. },

  37. onClickOp: function (btn) {

  38. if(this.state.selectedOperator!=null && this.state.numberClicked===true){

  39. var vm = this.getViewModel();

  40. var op2 = parseFloat(vm.get('display'));

  41. var op1 = parseFloat(this.state.op1);

  42. var result = 0;

  43. switch(this.state.selectedOperator){

  44. case '+':

  45. result = op1 + op2;

  46. break;

  47. case '-':

  48. result = op1 - op2;

  49. break;

  50. case '×':

  51. result = op1 * op2;

  52. break;

  53. case '÷':

  54. result = op1 / op2;

  55. break;

  56. }

  57. vm.set('display', Math.round(result * 100) / 100);

  58. this.state.selectedOperator=null;

  59. }

  60. if(btn.text!='=') {

  61. this.state.operatorClicked = true;

  62. }

  63. this.state.selectedOperator = btn.text;

  64. this.state.numberClicked = false;

  65. },

  66. onClickDot: function (btn) {

  67. if(this.state.decimal===false) {

  68. var vm = this.getViewModel();

  69. vm.set('display', vm.get('display') + '.');

  70. }

  71. },

  72. onClickNumber: function (btn) {

  73. this.state.numberClicked = true;

  74. if(this.state.selectedOperator ==='='){

  75. this.onClickClear();

  76. }

  77. var vm = this.getViewModel();

  78. if(this.state.operatorClicked===true) {

  79. this.state.op1= vm.get('display');

  80. vm.set('display', btn.text);

  81. this.state.operatorClicked=false;

  82. }else{

  83. var cur = vm.get('display');

  84. if(cur == '0') {

  85. cur = '';

  86. }

  87. vm.set('display', cur + btn.text);

  88. }

  89. }

  90. });


 

 

 

檢視模型 — MainViewModel.js

這個 ViewModel 只有一個屬性為 display 。這個用來繫結到計算器顯示的值上。這裡我們不會分別用一組欄位建立模型,此外我們還將會硬編碼資料。

 

 
  1. Ext.define('Calc.view.main.MainModel', {

  2. extend: 'Ext.app.ViewModel',

  3. alias: 'viewmodel.main',

  4. data: {

  5. display: 0.0

  6. }

  7. });

 

 

在即將到來的章節中你將學習更多關於 模型,檢視模型,欄位,欄位型別,校驗 等等。

 

總結

在本章中,你瞭解了不同的基本元件,例如 文字框,數字框,按鈕,選單等等。你已經學會如何使用表單欄位設計一個表單和我們之前建立了一個簡單的計算器專案。

在下一章中,你將學習關於資料包的內容,例如 資料來源 ,模型 ,代理等等。store ,model ,這將是有益於處理資料的。