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>

 結果是這樣的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM