1

假设你有以下js:

  var vm = {
    objects: ko.observable([]),
    objectCount: ko.computed(function(){
      return vm && vm.objects().length;
    }),

    add: function() {
      var current = vm.objects();
      current.push({});      
      console.log('current is', current);
      vm.objects(current);
      console.log("should recalculate here", vm.objectCount());
    }
  };

以及以下html:

  <ul data-bind="foreach: objects">
    <li>
      Object: <span data-bind="text: $index"></span>
    </li>
  </ul>
  <button data-bind="click: add">Add Object</button>
  <p>
    Total number of objects:
    <span data-bind="text: objectCount"></span>
  </p>

从阅读文档中我的理解是,因为在我添加了一个调用 objectCount() 的对象后,它应该重新计算它的依赖关系。相反,它似乎甚至从未执行过该功能,只运行一次!

JSBin 演示了我的问题的简化版本。

4

3 回答 3

4

在定义你的 viewModel 工作后定义你的计算 - http://jsbin.com/welcome/58760/ - 它发生是因为计算的 observables 的工作方式(来自 ko docs)。

  1. 每当你声明一个计算的 observable 时,KO 立即调用它的求值函数来获取它的初始值。
  2. 当您的评估器功能运行时,KO 会记录您的评估器读取其值的任何可观察对象(或计算的可观察对象)。
  3. 当你的评估器完成后,KO 为你接触过的每个可观察对象(或计算的可观察对象)设置订阅。订阅回调设置为使您的
    评估程序再次运行,
    将整个过程循环回第 1 步(处理任何
    不再适用的旧订阅)。
  4. KO 通知任何订阅者你计算的 observable 的新值。

在 vm 对象中实例化 observable 时,其他属性还不存在。

于 2012-12-07T17:07:57.387 回答
2

这只是一个范围界定问题。如果您将脚本代码重构为如下所示:

$(function(){
  var vm = function(){
    var self = this;

    self.objects = ko.observable([]);
    self.objectCount = ko.computed(function(){
      return self.objects().length;
    });

    self.add = function() {
      var current = self.objects();
      current.push({});      
      console.log('current is', current);
      self.objects(current);
      console.log("should recalculate here", self.objectCount());
    };
  };

  ko.applyBindings(new vm());
});

然后确定正确的变量范围,并且 Knockout 正确计算依赖关系。如guigouz所述,ko.computed最初调用的vm时间是未定义的,因此它无法设置任何更改处理程序。

这是更新的 JSBin

于 2012-12-07T17:03:37.357 回答
2

deferEvaluation另一种方法是使用ko.computed. 这将告诉 Knockout 等待计算计算的 observable 直到它第一次使用。到那时,vm将被定义。

objectCount: ko.computed(function(){
  return vm && vm.objects().length;
}, null, { deferEvaluation: true }),
于 2012-12-07T20:55:41.713 回答