第二篇要來講解Model的部分了,本篇會以去早餐店點餐為例。
Model可以當作就是物件導向裡的物件,建立好一個Model樣板後就可以建立許多該物件
以早餐店為例,每一個顧客就是一個Model,每個顧客會有三個屬性:號碼牌的號碼、餐點、價格
所以我們先寫一個Model出來:
//顧客model
function OrderMeal(number, meal) {
var self = this;
self.number = ko.observable(number); //號碼
self.meal = ko.observable(meal); //餐點
//顯示費用
self.price = ko.computed(function () {
return "新台幣 " + self.meal().price + " 元";
})
}
在建立每個物件時,我需要傳入兩個參數:號碼與餐點
而傳入的參數會帶進屬性裡面,因號碼與餐點還有可能會變動
所以用ko.observable來觀察該屬性,而後面的價格我們稍會再談
Model處理好後,下一步就是建立菜單,菜單部分程式碼如下:
//可選擇餐點的model 想成來自資料庫的資源 不能更動
self.chooseMeals = [
{ mealName: "套餐一(豬排蛋堡 + 大杯飲料)", price: 40 },
{ mealName: "套餐二(黑胡椒鐵板麵 + 蛋 + 大冰紅)", price: 55 },
{ mealName: "套餐三(咔拉雞腿堡 + 厚片系列 + 大杯飲料)", price: 80 },
{ mealName: "兒童餐(脆薯 + 麥克雞塊 + 兒童漢堡 + 大杯飲料)", price: 100 }
]
菜單陣列裡會有多個物件,每個物件就是一個套餐的資訊,會包含套餐名稱與價格
而在實際應用時會用Ajax或其他方法將要顯示的內容載入,所以這部分通常不會變動,也就不用去觀察它
再來就是本篇的重點了,我們要建立一個已點餐的顧客陣列,程式碼如下:
//已點餐的顧客
self.orders = ko.observableArray([
new OrderMeal("1", self.chooseMeals[1]),
new OrderMeal("2", self.chooseMeals[2])
])
首先,一個顧客就是一個物件(Model)
所以要儲存所有顧客的資料,就得建立一個陣列
而KO觀察陣列的方法是ko.observableArray
使用此方法後,若陣列有所變動(增加物件---新增顧客;減少物件---刪除顧客,等等會提到應用)KO就會立即反映到頁面上
一開始我們先預設建立兩個物件,分別傳入號碼與餐點,self.chooseMeals[1]就是套餐二、self.chooseMeals[2]為套餐三
以此類推。再回到Model的程式碼,其中一段為:
//顯示費用
self.price = ko.computed(function () {
return "新台幣 " + self.meal().price + " 元";
})
費用的部分使用了一個方法為ko.computed,可以把這個方法想成對某個屬性加工
以本例來說,self.meal()代表的是該顧客所點的餐點
而餐點裡面有餐點名稱(mealName)和價錢(price)
所以我想要取得餐點價格的話就要用self.meal().price來取得價錢
而meal要加括號的原因,是因為self.meal這個變數我已經使用ko.observable這個方法來觀察
所以想要讀取該方法的值的話就需要加括號
取得了價錢之後,我在前後加上想要的字串,這樣我若想讀取model的price屬性
就會顯示return的結果,而且如果self.meal()有變動,ko.computed會自動偵測並跟著變動
以上建立好之後,就可以開始對view的部分進行撰寫,程式碼如下:
<strong>等待取餐</strong>
<table border="1" style="border-style:dashed;">
<thead>
<tr>
<th>號碼</th>
<th>餐點</th>
<th>費用</th>
</tr>
</thead>
<tbody data-bind="foreach: orders">
<tr>
<td><span data-bind="text: number"></span></td>
<td><span data-bind="text: meal().mealName"></span></td>
<td><span data-bind="text: meal().price"></span></td>
</tr>
</tbody>
</table>
顯示結果為:在tbody的部分加上data-bind=”foreach:orders”,KO會利用迴圈的方式
將顧客陣列(orders)的每一個顧客資料(model)顯示出來
而想要顯示什麼內容就設定在tbody標籤內,裡面我設定顯示號碼、餐點與價格的部分
若要修改每一個顧客的資料要怎麼處理呢?首先頁面的程式碼如下:
<strong>設定取餐</strong>
<table border="1" style="border-style:dashed;">
<thead>
<tr>
<th>號碼</th>
<th>餐點</th>
</tr>
</thead>
<tbody data-bind="foreach: orders">
<tr>
<td><input data-bind="value: number"></td>
<td><select data-bind="options: $root.chooseMeals, value:meal, optionsText: 'mealName'"></select></td>
<td><button data-bind="click: $root.removeOrder">刪除</button></td>
</tr>
</tbody>
</table>
顯示結果為:大部分前面都有提過,而這裡要講解的是select的操作
在select裡的data-bind有三個參數,第一個是options
將你要顯示的選單內容放到該位置,本例是放置chooseMeals
但前面必須要加上$root,因為我們目前的位置是在foreach裡的model物件
這個物件並沒有chooseMeals,若我們想要往上一層到ViewModel就必須要加上$root
第二個value就是選單的值要帶入的變數名稱
當我們選擇了一個選項,就會取得該選項的值,而該值就會帶到model裡面的meal變數
反過來說,當我們設定了meal變數的值,選單就會自動對應到該選項
所以顯示結果的畫面是頁面一載入時,選單自動選擇的選項
第三個optionsText則是要顯示的選項名稱,而這裡是設定為chooseMeals裡每一個物件的mealName
讓我們來點選一下選單點選兒童餐後
當點選了兒童餐後,後面的價格也跟著變動了
另外補充,若你想存入的是單一個值而不是物件,則可以加入第四個參數:optionsValue
該參數可以設定選項要存入什麼值
由於本例沒有使用該參數,KO會直接將選項的值設為整個餐點物件
若你只想要取得餐點的價格,可以設定為optionsValue:'price'
系統會讀取每個套餐物件的price值並設定為該選項的值,當然相關的程式碼也要跟著作調整,完整data-bind參數為:
options: $root.chooseMeals, value:meal, optionsText: 'mealName',optionsValue:'price'
由於篇幅過多,後續內容會擺到第三篇來講。