本文是【Knockout.js 學習體驗之旅】系列文章的第3篇,所有demo均基於目前knockout.js的最新版本(3.4.0)。小茄才識有限,文中若有不當之處,還望大家指出。 目錄: 【Knockout.js 學習體驗之旅】(1)ko初體驗 【Knockout.js 學習體驗之旅】(2)花式捆 ...
本文是【Knockout.js 學習體驗之旅】系列文章的第3篇,所有demo均基於目前knockout.js的最新版本(3.4.0)。小茄才識有限,文中若有不當之處,還望大家指出。
目錄:
模板引擎
頁面是由數據和HTML組件構成的,如何將數據嵌入到HTML組件裡面呢?一個比較好的選擇是使用模板技術。
回顧下第一篇(【Knockoutjs 學習體驗之旅】(1)ko初體驗)開頭的總價計算:
1 <!--HTML Code--> 2 <div class="counter"> 3 Price: <input type="text" data-bind="{value: price, valueUpdate: 'afterkeydown'}" placeholder="請輸入單價" /><br /> 4 Account: <input type="text" data-bind="textInput: account" placeholder="請輸入個數" /><br /> 5 sum: <span data-bind="text: sum"></span> 6 </div>
這就是一個簡單的組件,他有自己的內部結構,有自己的事件處理機制。假如我需要使用很多個這樣的組件,那肯定不會是將上面的HTML代碼複製 n 遍插入到不同的地方吧,況且單純複製還不行,還要將變數區分開呢!如果是在一個列表裡面,那可以用 foreach 來做,如果是要用在不同的容器內,那就要使用模板引擎技術了。
模板技術並不是什麼高深的東西,有基於字元串拼接技術的,有基於 DOM 節點的,還有混合著的。更具體的介紹可以看一看這個輪子哥的文章 http://www.tuicool.com/articles/qMJ77r,樓主就不班門弄斧了。knockout.js 也是基於DOM節點的模板技術,編譯之後 view 與 data 還是保持綁定關係,可以簡單方便地更新數據到 view 層。另外你也可以將 knockout.js 鏈接到第三方的模板引擎,如 jquery.tmpl 和 Underscore等模板引擎。
下麵簡單講講ko中模板綁定的使用,第三方的集成引用不在本文討論範圍內。
knockout.js 的模板綁定
先看一個例子:
1 <h2>Participants</h2> Here are the participants: 2 <div data-bind="template: { name: 'person-template', data: buyer }"></div> 3 <div data-bind="template: { name: 'person-template', data: seller }"></div> 4 5 <!--模板--> 6 <script type="text/html" id="person-template"> 7 <h3 data-bind="text: name"></h3> 8 <p>Credits: <span data-bind="text: credits"></span></p> 9 </script> 10 11 <script type="text/javascript"> 12 function MyViewModel() { 13 this.buyer = { name: 'Franklin', credits: 250 }; 14 this.seller = { name: 'Mario', credits: 5800 }; 15 } 16 ko.applyBindings(new MyViewModel()); 17 </script>
<script type="text/html" id="person-template">這個script腳本標簽定義了一個 id 為"person-template"的模板,ko就是通過這個 id 來尋找相應的模板。註意這個腳本的 type 是"text/html",所以才能跟正常的腳本區分開。ko不會自動綁定在這種腳本內的代碼,只有在這個模板被使用的時候才會去綁定。
使用方法:HTML元素中使用 data-bind 綁定用到的模板,在 js 中定義相應的數據並應用該綁定。可以看到上面的"person-template"被引用了兩次,一次使用的是buyer的數據,另一次使用了seller數據。下麵簡單說說模板綁定中用到的參數:
- name — 指定你要渲染的模板片段,跟模板腳本中的 id 相對應。
- nodes — 直接傳遞一個DOM節點數組作為模板使用。傳遞的DOM節點數列應該是不被監控的,因為渲染過程中會對這個節點數列進行複製賦值等操作。而且如果這個節點數組有父級節點的話也會被移除。當我們傳遞了一個非空的name值時,nodes選項會被忽略,所以很少會用到這個屬性。
- data — 用來作為渲染數據的對象。如果你忽略整個參數,KO將查找foreach參數,或者是應用整個view model對象。
- if — 與上一篇中的 if 作用類似,只有當 if 後的表達式為真時才會渲染模板,用於防止一個空可觀察對象在模板被填充之前被綁定。
- foreach — 按照“foreach”模式渲染模板。
- as — 結合foreach使用的時候,指定每項渲染數據的別名,主要是用於定義數據範圍方便在嵌套綁定裡面使用。
- afterRender, afterAdd, or beforeRemove — 渲染時的回調函數。
下麵簡單簡單介紹一下幾種用法。
一些例子
- 使用 foreach 渲染 ViewModel中的所有數據
1 <h2>Participants</h2> 2 Here are the participants: 3 <div data-bind="template: { name: 'person-template', foreach: people }"></div> 4 5 <script type="text/html" id="person-template"> 6 <h3 data-bind="text: name"></h3> 7 <p>Credits: <span data-bind="text: credits"></span></p> 8 </script> 9 10 function MyViewModel() { 11 this.people = [ 12 { name: 'Franklin', credits: 250 }, 13 { name: 'Mario', credits: 5800 } 14 ] 15 } 16 ko.applyBindings(new MyViewModel());
這個例子跟上面的例子效果是一樣的,使用 foreach 會將所有數據都渲染到模板中。區別就在於HTML的層級,使用data指定的時候,每一份數據渲染到對應的容器中;使用foreach的時候所有數據都被綁定到了一個容器內。上一篇中也介紹了foreach的用法,用不用模板都能得到一樣的效果。回憶一下foreach的寫法:
1 <div data-bind="foreach: people"> 2 <h3 data-bind="text: name"></h3> 3 <p>Credits: <span data-bind="text: credits"></span></p> 4 </div>
- as 在嵌套綁定中的使用
1 <ul data-bind="template: { name: 'seasonTemplate', foreach: seasons, as: 'season' }"></ul> 2 3 <script type="text/html" id="seasonTemplate"> 4 <li> 5 <strong data-bind="text: name"></strong> 6 <ul data-bind="template: { name: 'monthTemplate', foreach: months, as: 'month' }"></ul> 7 </li> 8 </script> 9 10 <script type="text/html" id="monthTemplate"> 11 <li> 12 <span data-bind="text: month"></span> 13 is in 14 <span data-bind="text: season.name"></span> 15 </li> 16 </script> 17 18 <script> 19 var viewModel = { 20 seasons: ko.observableArray([ 21 { name: 'Spring', months: [ 'March', 'April', 'May' ] }, 22 { name: 'Summer', months: [ 'June', 'July', 'August' ] }, 23 { name: 'Autumn', months: [ 'September', 'October', 'November' ] }, 24 { name: 'Winter', months: [ 'December', 'January', 'February' ] } 25 ]) 26 }; 27 ko.applyBindings(viewModel); 28 </script>
上面這種多層的綁定中,要在下級綁定層次中要引用上層的話,就可以使用 as 定義的別名了。當然層次簡單的時候,用$parent也是可以的,用 as 會更加清晰,不會糾結在層次關係中。
註意:as 後接的別名應該用引號引起來,因為這裡我們是命名一個變數,而不是讀取一個已經存在的變數。
- 動態決定使用哪個模板
1 <ul data-bind='template: { name: displayMode, foreach: employees }'> </ul> 2 <script id="active" type='text/html'> 3 <li><span data-bind='text: name'></span>uses the "active" template!</li> 4 </script> 5 <script id="inactive" type='text/html'> 6 <li><span data-bind='text: name'></span>uses the "inactive" template!</li> 7 </script> 8 9 <script> 10 var viewModel = { 11 employees: ko.observableArray([{ 12 name: "Kari", 13 active: ko.observable(true) 14 }, { 15 name: "Brynn", 16 active: ko.observable(false) 17 }, { 18 name: "Nora", 19 active: ko.observable(false) 20 }]), 21 displayMode: function(employee) { 22 // Initially "Kari" uses the "active" template, while the others use "inactive" 23 return employee.active() ? "active" : "inactive"; 24 } 25 }; 26 // ... then later ... 27 viewModel.employees()[1].active(true); 28 // Now "Brynn" is also rendered using the "active" template. 29 ko.applyBindings(viewModel); 30 </script>
上面這個例子有 active 和 inactive 兩個模板,ul 元素的 name 沒有直接指定模板 id ,而是通過一個函數返回模板 id,達到了選擇不同模板的目的。
吐槽一下:官方的文檔相當省,模板腳本都省掉了。。。博客園的湯姆大叔,居然也就那樣搬下來了,純翻譯的讓人無語。
Mapping插件
模板技術可以簡單地將數據和表現分離,採用前端渲染技術時,後臺只要將模型數據發給客戶端即可,前端將獲取到的數據渲染輸出。目前為止都是手動將獲取到的數據寫入 ViewModel 中,而 Mapping 插件就是幫你自動完成創建 ViewModel 的好工具。對比一下手動創建和使用 Mapping 插件兩種方式:
手動創建:
1 // setup 2 var viewModel = { 3 serverTime: ko.observable(), 4 numUsers: ko.observable() 5 } 6 // update: 7 var data = getDataUsingAjax(); // your method to get data from server 8 viewModel.serverTime(data.serverTime); 9 viewModel.numUsers(data.numUsers);
Mapping插件
1 var data = getDataUsingAjax(); // your method to get data from server 2 var viewModel = ko.mapping.fromJS(data); 3 ko.mapping.fromJS(data, viewModel);
假如從伺服器中獲取的數據比較多的話,使用Mapping的確可以減少很多代碼量。使用Mapping之後,data對象的所有屬性都被設置成可觀察對象,所有數組都被設置成可觀察對象數組,數組中的順序依然被保存。改變data對象的屬性或者增減數組項目就可以引起綁定更新事件。Mapping插件還有很多高級用法,不過除非非Mapping插件不可的情況,沒必要對一個插件投入太多精力去學習,搞太多還不如手寫算了。
總結
本篇主要簡單介紹了knockoutjs中模板技術的使用,感覺 ko 中用到的技術應該也差不多就這些了,自定義綁定和組件綁定相關的內容暫時沒有用到就不去深究了。組件的寫法有很多種,不一定要用 ko 的組件封裝規則,各有所好。 下一篇將會用一個綜合實例來介紹 ko 的各種綁定用法,敬請期待~~
碼字不易,隨手點贊哈~~~
參考資料:
- 官方教程: http://knockoutjs.com/documentation/introduction.html
- 湯姆大叔教程(官方教程翻譯,版本太舊,信息缺失明顯): http://www.cnblogs.com/TomXu/archive/2011/11/21/2257154.html
- 一個對前端模板技術的全面總結: http://www.tuicool.com/articles/qMJ77r
文字較多,慣例湊圖!
(圖片來源:網路)
原創文章,轉載請註明出處!本文鏈接:http://www.cnblogs.com/qieguo/p/5579888.html