0

我有一个应用程序,其中对象可能位于多个列表之一中。一个列表的 UI 需要将每个项目标记为在其他列表之一上。

我实现的一个非常简化的版本是这样的:

function Item(id, panel) {
    var that = this;
    this.id = id;
    this.viewModel = panel;
    this.isSelected = ko.computed(function(){
        return panel.isSelected(that);
    });
}

function Panel() {
    var that = this;

    //my two lists
    this.all = ko.observableArray();
    this.selected = ko.observableArray();

    this.isSelected = function(item){
        return _(that.selected()).find(function(thing){
            console.log("iterating");
            return thing.id == item.id;
        });
    };
}

var panel = new Panel();
ko.applyBindings(panel);

//add some things to the list
for(var i=0; i<40; i++){
    var item = new Item(i, panel)
    panel.all.push(item);
    //let's select some of them. note it's actually a different object
    if (i % 2 == 0){
        panel.selected.push(new Item(i, panel));
    }
};
​

小提琴在这里:http: //jsfiddle.net/89j52/5/

因此,除了将项目提供给面板的参考之外,它的表现也很糟糕。这是因为每次您将另一个项目添加到选定列表时,它都会重新计算所有项目的选定状态;注意它打印了多少次“迭代”。我明白为什么会这样,但很痛苦。

现在很明显,我每次添加时都不需要检查每个项目。例如,我可以为项目存储一个查找表,然后在将某些内容添加到所选列表时更新正确的查找表。但我不知道如何将其与 Knockout 的可观察/计算的东西结合起来,并使 UI 更新无缝。我应该如何在 Knockout 的习语中解决这个问题?

4

1 回答 1

1

如果您将isSelected转换为常规 observable(未计算)并在每次将项目添加到选定列表时直接更新它会怎样:

function select(item){
    panel.selected.push(item);
    var itemInAll = _(panel.all()).find(function(thing){
        return thing.id === item.id;
    });
    itemInAll.isSelected(true);
}

不是很优雅,但绝对更有效率。您也不需要在Item中保留对面板的引用。这是完整的代码:http: //jsfiddle.net/89j52/9/

于 2012-04-04T13:51:06.013 回答