zoukankan      html  css  js  c++  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="300px;">
                        ID
                    </th>
                    <th style="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="300px;">
                        ID
                    </th>
                    <th style="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>

     结果是这样的。

  • 相关阅读:
    一步一步教你elasticsearch在windows下的安装
    Query DSL for elasticsearch Query
    [转] webpack之前端性能优化(史上最全,不断更新中。。。)
    [转] Javascript模块化编程(一):模块的写法
    [转] 2016 JavaScript 发展现状大调查
    [转] 前端性能的几个基础指标
    [转] 视频直播前端方案
    [转] Web前端开发工程师常用技术网站整理
    [转] getBoundingClientRect判断元素是否可见
    [转] js前端解决跨域问题的8种方案(最新最全)
  • 原文地址:https://www.cnblogs.com/shanhe/p/4499554.html
Copyright © 2011-2022 走看看