0

想象一个按姓名排序的联系人数组。这个数组可以像这样输出:

<ul data-bind="foreach: contacts>
    <li data-bind="text: name"></li>
</ul>

我想做的是为每个具有不同起始字母的 li 指定一个标题,例如显示 A、B、D ...

- A
- Anderson
- Andrews
- B
- Bellamy
- D
- Davidson
- Davis

在普通的编程语言中,我会定义一个包含名称第一个字母的变量,并在 foreach 循环中检查它是否不同。如果是这种情况,则显示标题。

我应该如何使用 knockout.js 执行此操作?

4

2 回答 2

1

这是一种坚持淘汰模式的方法。首先,您将创建一个计算的 observable,将您的数组映射到一个按字母分组的新数组。

self.contactsByLetter = ko.computed(function () {
    var result = [],
        currentLetter, currentGroup;
    ko.utils.arrayForEach(self.contacts(), function (contact) {
        if (contact.name[0] !== currentLetter) {
            currentLetter = contact.name[0];
            currentGroup = {
                letter: currentLetter,
                contacts: []
            }
            result.push(currentGroup);
        }
        currentGroup.contacts.push(contact);
    })
    return result;
});

那么您的 HTML 将只需要两个循环。

<ul data-bind="foreach: contactsByLetter">
    <li class="heading" data-bind="text: letter"></li>
    <!--ko foreach: contacts-->
    <li data-bind="text: name"></li>
    <!--/ko-->
</ul>

jsFiddle:http: //jsfiddle.net/mbest/ZcQT4/

于 2013-02-14T21:36:58.207 回答
0

不确定这是否是更清洁的方式,但您可以使用固定数组来存储字母,然后在视图模型上使用方法来仅返回以第 n 个字母开头的项目 - 即

<ul data-bind="foreach: letters">
    <li data-bind="text: $data">
        <ul data-bind="foreach: $parent.contactsStartingWith($data)">
             <li data-bind="text: name"></li>
        </ul>
    </li>
</ul>

其中contactsStartingWith可以定义为:

function(start) {
    return ko.utils.arrayFilter(contacts(), function(it) { return it.name()[0].toUpperCase() == start } );
}

...并且字母数组可以很容易地提取为:

viewModel.letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");

(关于使用数组的淘汰工具的一些有用参考:http ://www.knockmeout.net/2011/04/utility-functions-in-knockoutjs.html )

于 2013-02-14T21:32:22.907 回答