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>

结果是这样的。

时间: 2024-08-28 12:42:35

knockout 无容器绑定,多重foreach,获取当前 索引 父级索引的相关文章

js获取iframe和父级之间元素,方法、属,获取iframe的高度自适应iframe高度

摘自:http://blog.csdn.net/kongjiea/article/details/38870399 1.在父页面 获取iframe子页面的元素 (在同域的情况下 且在http://下测试,且最好在iframe onload加载完毕后 dosomething...) js写法 a.同过contentWindow获取 也有用contentDocument 获取的 但是contentWindow 兼容各个浏览器,可取得子窗口的 window 对象.contentDocument Fir

dirname的用法:获取文件的父级目录路径

命令:dirname 获取文件的路径(到父级目录)用法:dirname file_name [[email protected] opt]# a=$(dirname /mnt/a/b/c/d/a.sh) [[email protected] opt]# echo $a /mnt/a/b/c/d 原文地址:https://www.cnblogs.com/kaishirenshi/p/10277997.html

在iframe子页面中获取并操作父级页面的对象/元素

//获取iframe的window对象 // var gbiframe = window.top.document.getElementById("gbiframe").contentWindow; // 通过获取到的window对象操作HTML元素,这和普通页面一样 // var val = gbiframe.document.getElementById("gbaddr").value; // alert(val); 只有FF能使用

根据子级ID获取其所有父级

当前位置>新闻中心>行业资讯 CLASSID CLASSNAME CLASSPID 1 新闻中心 0 2 行业资讯 1 3 公司新闻 1 4 媒体聚焦 0 当前位置<%=navName %> public string navName = ""; protected void getNav(string str) { if (str != "0") { navName = ">" + new BLL.TB_CLASS

KnockOut 绑定之foreach绑定(mvc+knockout)

什么时候使用foreach绑定 foreach绑定对于数组中的每一个元素复制一节标记语言,也就是html,并且将这节标记语言和数组里面的每一个元素绑定.当我们呈现一组list数据,或者一个表格的时候,十分有用. 如果你绑定的数组是一个"监控数组" ,observable array,(和wpf里面的ObservableCollection<T>差不多).当你添加或移除,或者重新排序数组里面的元素的时候,会动态的更新UI界面.并且此时并不会影响原先的DOM元素.这样比我们直接

获取元素父级方法

1:parent();//获取元素的父级元素 <script type="text/javascript" src="jquery-1.11.1.js"></script> <script> $(function(){ $('span').parent().css('border','2px solid red');//获取到div元素 }) </script> </head> <body> &

基于jquery的表格动态创建,自动绑定,自动获取值

最近刚加入GUT项目,学习了很多其他同事写的代码,感觉受益匪浅. 在GUT项目中,经常会碰到这样一个问题:动态生成表格,包括从数据库中读取数据,并绑定在表格中,以及从在页面上通过jQuery新增删除表格.如下所示: 在实现过程中,开发人员经常采用如下方式来实现: 1)          在前台,通过js生成表格行的html字符串,然后通过jquery的after方法加到表格底部. 2)          在后台,读取数据库,然后生成表格的html字符串,然后传递给前台渲染 3)         

文件无刷新上传并获取保存到服务器端的路径(swfUpload与uploadify)

文件无刷新上传并获取保存到服务器端的路径 遇到上传文件的问题,结合之前用到过的swfUpload,又找了一个无刷新上传文件的jquery插件uploadify,写篇博客记录一下分别介绍这两个的实现方法 swfUpload 导入swfUpload的开发包 添加js引用,引用swfUpload.js与handler.js文件,如果对swfUpload不了解.有疑问可以看看这篇博客 页面初始化 修改handler.js文件中 上传成功的事件,serverData是服务器端的响应 Uploadify 导

WPF绑定的ListBox获取ListBoxItem及GoToState应用

现公司项目中需要制作一个扇形菜单,菜单项是用ListBox重写Style实现的,其数据是绑定的.菜单的每一项都有Normal,MouseOver和Selected三种状态,这三种状态当然可以通过鼠标移动和点击控制,但现在要通过代码来改变控件外观实现三种状态切换,该如何处理呢?   1.WPF绑定的ListBox获取ListBoxItem WPF中如果ListBox的ItemSource为绑定的,则ListBox.Items为绑定的数据源,而非ListBoxItem.如果直接通过如下代码会发现无法