在使用knockout過程當中 發現jquery tmpl 在循環上性能不好。通過多方查詢得知 knockout 其實有 本身的 無容器綁定。javascript
那麼廢話少說如今開始。html
一、後臺模型展現java
爲了構建更生動的數據源咱們先聲明一個類,起名叫 User 這個類的接口一眼就看穿了,須要注意的地方就是 每一個User 都有一個 UserFriends的集合。jquery
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WebSite.ViewModels { public class User { public Guid UserId { get; set; } public string UserName { get; set; } public List<User> UserFriends { get; set; } } }
二、構建數據源。。。此處省略吧。本身new個數組就好了,我直接粘貼代碼。json
這裏面比較生僻的 地方 是 SerializeHelper這個類是咱們本身封裝的,而這句話 ser.Serializer(users) 其實返回的就是一個json串。api
這裏在囉嗦一句,咱們都知道json傳 爲string類型。那麼爲何 return View(ser.Serializer(users)); 不這麼寫呢。數組
這個源於 mvc View(string ViewName)有個重載方法。你直接寫string 他就當成 視圖名稱了。mvc
固然還有個重載 叫 View(object obj); 這個 就是 頁面要的model了。app
public ActionResult NoWarp() { DotNet.Common.Json.SerializeHelper ser = new DotNet.Common.Json.SerializeHelper(); List<User> users = new List<User>(); for (int i =1; i <= 10; i++) { users.Add(new User() { UserId = Guid.NewGuid(), UserName = "崔" + i, UserFriends = new List<User>() { new User(){ UserId=Guid.NewGuid(), UserName="蚊子"+i }, new User(){ UserId=Guid.NewGuid(), UserName="#總"+i }, new User(){ UserId=Guid.NewGuid(), UserName="老郭"+i }, new User(){ UserId=Guid.NewGuid(), UserName="DK"+i }, } }); } return View(new MvcHtmlString(ser.Serializer(users))); }
三、頁面性能
上面咱們 new MvcHtmlString 那麼頁面上就須要經過這個類型把他接過來。 注意代碼第一行 @model MvcHtmlString 記得必定要用mvchtmlstring 要否則會被直接轉義。
到這裏準備工做就作完了。
相信用knockout的對上面都不陌生。
knockout 自己提供了 無容器綁定。
具體實現 你們直接看就好了。
值得注意的是,在循環中 如何獲取 item1 item2 的索引
在當前循環中獲取 索引 $index
獲取上一層循環索引 $parentContext.$index
在上一次的索引 $parentContext.$parentContext.$index
無限級 $parentContext....$parentContext.$index
如下是完整頁面代碼。
@model MvcHtmlString @{ ViewBag.Title = "NoWarp"; } @*<script src="~/Assets/plugins/knockout.js"></script>*@ @*layout中已經引用jquery和knockout這裏就不在提了*@ <h2>NoWarp</h2> <div id="pageUsers"> <table class="table table-striped table-advance"> <thead> <tr> <th style="width:300px;"> ID </th> <th style="width:150px"> 姓名 </th> <th> 朋友們 </th> </tr> </thead> <tbody> <!--ko foreach:{data:Users,as:'iuser'}--> <tr> <td> <!--ko text:iuser.UserId--> <!--/ko--> </td> <td> <!--ko text:iuser.UserName--> <!--/ko--> </td> <td data-bind="foreach:{data:iuser.UserFriends,as:'ifriend'}"> <!--ko text:ifriend.UserName--> <!--/ko--> <!--ko if:$index()<iuser.UserFriends.length-1 -->,<!--/ko--> <!--ko if:$index()==iuser.UserFriends.length-1&&$parentContext.$index()==3--> <span style="color:red">*</span> <!--/ko--> </td> </tr> <!--/ko--> </tbody> </table> </div> <script> var ViewModel = { Users: ko.observableArray(eval('(' + '@Model' + ')')) }; $(function () { ko.applyBindings(ViewModel, $("#pageUsers")[0]); }); </script>
進階篇
下面開始增長難度,來個刪除功能。
咱們都知道 數組中 刪除 是這麼寫的 array.splice(index,length);
上面咱們能夠獲取索引 那麼刪除 就能夠寫了。上代碼
先來正常的邏輯
<td data-bind="foreach:{data:iuser.UserFriends,as:'ifriend'}"> <!--ko text:ifriend.UserName--> <!--/ko--> <!--ko if:$index()<iuser.UserFriends.length-1 -->,<!--/ko--> <a href="javascript:;" data-bind="click:function(){iuser.UserFriends.splice($index(),1);}">刪除此朋友</a> <br/> <!--ko if:$index()==iuser.UserFriends.length-1&&$parentContext.$index()==3--> <span style="color:red">*</span> <!--/ko--> </td>
頁面生成以下
我點擊了刪除 發現 竟然無效。好的 那咱們加個debugger 看看 發生了什麼。。
好吧 從最開始就入坑了,你們都知道knockout 綁定 想要實現頁面聯動 必須聲明依賴屬性。咱們直接把json對象拿過來用。固然很差使了。
好的那咱們開始構建一個 user模型。
<script> function User(model) { this.UserId = ko.observable(model ? model.UserId : '空Id'); this.UserName = ko.observable(model ? model.UserName : '空Name'); var tmpF = []; if (model && model.UserFriends) { $(model.UserFriends).each(function (i, item) { tmpF.push(item); }); } this.UserFriends = ko.observableArray(tmpF); } var ViewModel = { Users: ko.observableArray([]) }; $(function () { $(eval('(' + '@Model' + ')')).each(function (i, item) { ViewModel.Users.push(new User(item)); }); ko.applyBindings(ViewModel, $("#pageUsers")[0]); }); </script>
好的模型轉換以後咱們看一下對象結構
好的,結構變成綁定數組了。ok 這個刪除也好使了。
還有在knockout綁定中
有 $parent 這個對象表明當前對象的父級。
$parents 表明當前對象綁定的 父級集合 $parents[0] 最近 $parents[n]。。無限級。
$element 表明當前綁定的元素。(無容器獲取不到。)
當官方文檔是 還有不少內置對象,咱們經常使用大概也就是這些。
對象詳細請參考:http://knockoutjs.com/documentation/binding-context.html
具體能夠參考:http://knockoutjs.com/
注意事項,在knockout 無容器綁定模版時 ,若是須要寫循環
能夠這麼寫。
我就手懶 直接在官方api上截圖了。
值得注意的是:模版中不能使用 foreach bind 和 if bind 目前發現這2個不能用。
若是模版套模版實現循環時能夠這麼寫。
我就不一一截圖吧,路子都在代碼裏。
直接上完整代碼
@model MvcHtmlString @{ ViewBag.Title = "NoWarp"; } @*<script src="~/Assets/plugins/knockout.js"></script>*@ @*layout中已經引用jquery和knockout這裏就不在提了*@ <h2>NoWarp</h2> <div id="pageUsers"> <table class="table table-striped table-advance"> <thead> <tr> <th style="width:300px;"> ID </th> <th style="width:150px"> 姓名 </th> <th> 朋友們 </th> <th> 操做 </th> </tr> </thead> <tbody> <!--ko template:{name:'tempate1',foreach:Users}--> <!--/ko--> <tr> <td colspan="4"> —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— </td> </tr> <!--ko foreach:{data:Users,as:'iuser'}--> <tr> <td> <!--ko text:iuser.UserId--> <!--/ko--> </td> <td> <!--ko text:iuser.UserName--> <!--/ko--> </td> <td data-bind="foreach:{data:iuser.UserFriends,as:'ifriend'}"> <!--ko text:ifriend.UserName--> <!--/ko--> <!--ko if:$index()<iuser.UserFriends.length-1 -->,<!--/ko--> <a href="javascript:;" data-bind="click:function(){iuser.UserFriends.splice($index(),1);}">刪除此朋友</a> <br /> <!--ko if:$index()==iuser.UserFriends.length-1&&$parentContext.$index()==3--> <span style="color:red">*</span> <!--/ko--> </td> <td> <a href="javascript:;" data-bind="click:function(){Users.splice($index(),1);}">刪除用戶</a> </td> </tr> <!--/ko--> </tbody> </table> </div> <script> function User(model) { this.UserId = ko.observable(model ? model.UserId : '空Id'); this.UserName = ko.observable(model ? model.UserName : '空Name'); var tmpF = []; if (model && model.UserFriends) { $(model.UserFriends).each(function (i, item) { tmpF.push(item); }); } this.UserFriends = ko.observableArray(tmpF); } var ViewModel = { Users: ko.observableArray([]) }; $(function () { $(eval('(' + '@Model' + ')')).each(function (i, item) { ViewModel.Users.push(new User(item)); }); ko.applyBindings(ViewModel, $("#pageUsers")[0]); }); </script> <script type="text/html" id="tempate1"> <tr> <td> <!--ko text:$data.UserId--> <!--/ko--> </td> <td > <!--ko text:$data.UserName--> <!--/ko--> </td> <td data-bind="template:{templateOptions:{itemuser:$data,itemIndex:$index() },foreach:$data.UserFriends,name:'tempate2',as:'itemFriend'}"> </td> <td> <a href="javascript:;" data-bind="click:function(){$parent.Users.splice($index(),1);}">刪除用戶</a> </td> </tr> </script> <script type="text/html" id="tempate2"> @*這裏若是想過去 上級的 item 就須要用 templateOptions 做爲傳入參數。*@ <!--ko text:$item.itemuser.UserName--> <!--/ko--> 的朋友 <!--ko text:itemFriend.UserName--> <!--/ko--> <br/> </script>
結果是這樣的。