你的位置:首页 > Java教程

[Java教程]knockout 无容器绑定,多重foreach,获取当前 索引 父级索引


在使用knockout过程中 发现jquery tmpl  在循环上性能很差。经过多方查询得知 knockout 其实有 自己的 无容器绑定。

那么废话少说现在开始。

1、后台模型展示

为了构建更生动的数据源我们先声明一个类,起名叫 User 这个类的接口一眼就看穿了,需要注意的地方就是 每个User 都有一个 UserFriends的集合。

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; }  }}

2、构建数据源。。。此处省略吧。自己new个数组就行了,我直接粘贴代码。

这里面比较生僻的 地方 是 SerializeHelper这个类是我们自己封装的,而这句话 ser.Serializer(users) 其实返回的就是一个json串。

这里在啰嗦一句,我们都知道json传 为string类型。那么为什么 return View(ser.Serializer(users));  不这么写呢。

这个源于 mvc View(string ViewName)有个重载方法。你直接写string 他就当成 视图名称了。

当然还有个重载 叫 View(object obj); 这个 就是 页面要的model了。

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)));    }

3、页面

上面我们 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>

 结果是这样的。