【问题标题】:How to create a computed observable array in Knockout如何在 Knockout 中创建计算的可观察数组
【发布时间】:2012-07-03 04:06:09
【问题描述】:

我想知道如何创建一个计算的可观察数组。

在我的视图模型中,我有 2 个可观察数组,我想要一个计算的可观察数组,它只是两个数组的组合。

function ViewModel() {
    var self = this;
    self.listA= ko.observableArray([]);
    self.listB = ko.observableArray([]);
    self.masterList= //combine both list A and B

【问题讨论】:

    标签: knockout.js ko.observablearray computed-observable


    【解决方案1】:

    这将组合两个数组并返回组合列表。但是,它不是一个计算的可观察数组(不知道这是否可能),而是一个常规的计算可观察数组。

    self.masterList = ko.computed(function() {
        return this.listA().concat(this.listB());
    }, this);
    

    【讨论】:

    • 我相信这个答案对于大多数用例来说都是有缺陷的:计算出的 observable 的值是一个常规数组,而不是一个 observable 数组(大致在答案中说明)。因此,更新listAlistB 将完全替换数组本身,而不是更新其内容(这是我们在 99% 的情况下想要的)。 这意味着你不应该将视图绑定到这个 observable。 实际上,这个代码和它的非计算变体一样有用。查看不同方法的其他答案。
    • 在这种情况下它不起作用,但是淘汰插件knockout-projections 使用新的array change subscriptions 实现了更高效的计算可观察数组。该插件可以扩展以支持高效的 concat 操作。
    • 当你使用这样的策略时 self.masterList.push('element') 表示列表未定义。当您使用 ko sortable 等依赖项时,这一点变得至关重要
    【解决方案2】:
    self.masterList = ko.observableArray();
    ko.computed(function () {
        self.masterList(self.listA().concat(self.listB()));
    });
    

    在精神上类似于 Joe Flateau 的回答,但我认为这种方法更简单。

    【讨论】:

    • 这也是我打算这样做的方式,但是作为公认的答案,这是否仍然受到问题的影响?因为任何更改都会导致绑定到masterList 的任何视图被完全重绘?
    • @AdamLewis:是的,这确实重建了整个数组,并且取决于视图引擎,它可能会或可能不会为绑定到它的任何视图重新渲染整个 DOM 子图(但不一定,可能只是做一个差异并应用它)。请注意,它可能仍然是避免许多更新的最佳解决方案。这不是我概述的关于你提到的答案的问题,如果视图引擎捕获数组属性本身(而不是它的路径),那么它永远不会检测到你交换了数组(因为它是不可观察的)和因此永远不会更新
    • @tne 我现在正在使用这个答案,但它似乎真的很慢......也许我做错了什么。但是,这个解决方案是否破坏了 KO 的预期目的?还有另一种方法可以解决需要计算的可观察数组的问题吗?只是想知道这是否是在我(或任何)情况下使用的正确工具。
    • @Nate 只要您确实需要按特定顺序组合列表,这种方法就没有问题。我在这里只使用了concat,因为其他人都是,以便与其他答案进行比较。如果我要删除该要求,我可能会做不同的事情(因为确实,这很慢)。例如。 push/splice 元素直接。如果元素经常更改,那么我可能会使用链表而不是数组。也许您可以根据您的要求提出一个单独的问题。
    【解决方案3】:

    我知道这是一个老问题,但我想我会把我的答案扔在那里:

    var u = ko.utils.unwrapObservable;
    
    ko.observableArray.fn.filter = function (predicate) {
        var target = this;
    
        var computed = ko.computed(function () {
            return ko.utils.arrayFilter(target(), predicate);
        });
    
        var observableArray = new ko.observableArray(u(computed));
    
        computed.subscribe(function (newValue) { observableArray(newValue); });
    
        return observableArray;
    };
    

    【讨论】:

      【解决方案4】:

      observableArray 只是一个带有更多属性的 observable。因此,在闭包中返回数组的计算 observable 将被视为数组。

      【讨论】:

      • 嗯,有点。我刚刚对其进行了测试,似乎除非将其声明为可观察数组,否则不会为您分解出 shift 和 pop 等方法。
      • 为了像我这样的人以后发现这一点的好处:这不是真的,请参阅接受答案中的 cmets 了解原因
      【解决方案5】:

      我不确定这是否是最有效的选择 - 但它相当简单并且适合我。 ko.computed 返回一个 observable 数组,如下所示:

      self.computedArrayValue = ko.computed(function() {
          var all = ko.observableArray([]);
          ....
          return all(); 
      });
      

      代码的工作示例: html:

      <div data-bind="foreach: days">
          <button class="btn btn-default btn-lg day" data-bind="text: $data, click: $root.dayPressed"></button>        
      </div> 
      

      视图模型上的Javascript函数:

      self.days = ko.computed(function() {
          var all = ko.observableArray([]);
          var month = self.selectedMonth();   //observable
          var year = self.selectedYear();     //observable
          for (var i = 1; i < 29; i++) {
              all.push(i);
          }
          if (month == "Feb" && year % 4 == 0) {
              all.push(29);
          } else if (["Jan","Mar","May","Jul","Aug","Oct","Dec"].find((p) => p == month)) {
              [29,30,31].forEach((i) => all.push(i));
          } else if (month != "Feb") {
              [29,30].forEach((i) => all.push(i));                
          }
          return all(); 
      });
      

      【讨论】:

        猜你喜欢
        • 2014-12-28
        • 2018-09-08
        • 1970-01-01
        • 2014-01-25
        • 1970-01-01
        • 2016-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多