为什么子视图模型中的函数会导致父视图模型中的计算值被触发?

时间:2018-02-17 17:48:07

标签: javascript knockout.js

按下以下代码中的按钮可以做两件事:它在嵌套视图模型中执行一个函数,并在父视图模型中执行computed



var MasterViewModel = function () {
  var self = this;
  self.nested = new FirstViewModel();
  self.func = ko.computed (function() {
    var items = self.nested.array();
    alert("executed");
  });
}
var FirstViewModel = function () {
  var self = this;
  self.array = ko.observableArray([]);
  self.push = function () {
    self.array.push(new SecondViewModel());
    alert("pushed");
  }
}

var SecondViewModel = function () {
  var self = this;
  self.z = ko.observable();
}

var mvm = new MasterViewModel();
ko.applyBindings(mvm);

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
  <div data-bind="with: nested">
    <button data-bind="text: 'push me', click: push"></button>
  </div>
&#13;
&#13;
&#13;

但是,如果将computed更改为一个简单的函数,则在按下按钮时它不会执行。为什么呢?

&#13;
&#13;
var MasterViewModel = function () {
  var self = this;
  self.nested = new FirstViewModel();
  self.func = function() {
    var items = self.nested.array();
    alert("executed");
  };
}
var FirstViewModel = function () {
  var self = this;
  self.array = ko.observableArray([]);
  self.push = function () {
    self.array.push(new SecondViewModel());
    alert("pushed");
  }
}

var SecondViewModel = function () {
  var self = this;
  self.z = ko.observable();
}

var mvm = new MasterViewModel();
ko.applyBindings(mvm);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
  <div data-bind="with: nested">
    <button data-bind="text: 'push me', click: push"></button>
  </div>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

作为已接受答案的补充,我在此处张贴documentation的相关部分:

  

依赖关系跟踪如何运作

     

[...]

     

它实际上非常简单而且非常可爱。跟踪算法   是这样的:

     
      
  1. 每当你声明一个计算的observable时,KO立即调用它的赋值函数来获得它的初始值。
  2.   
  3. 当评估程序函数正在运行时,KO设置对任何可观察对象(包括其他计算的可观察对象)的订阅   评估员读。订阅回调设置为导致   评估器再次运行,将整个过程循环回到步骤1   (处理任何不再适用的旧订阅)。
  4.   
  5. KO通知任何订阅者有关您计算的observable的新值。
  6.   

如果您想阻止依赖项创建,请使用peek

  

Knockout的自动依赖性跟踪通常会做到这一点   你要。但有时您可能需要控制哪些可观察量   将更新您的计算的observable,尤其是如果计算的   observable执行某种操作,例如创建Ajax   请求。 peek函数允许您访问可观察或计算   可以观察而不创建依赖。

所以给定的代码将改为:

&#13;
&#13;
var MasterViewModel = function () {
  var self = this;
  self.nested = new FirstViewModel();
  self.func = ko.computed (function() {
    var items = self.nested.array.peek();
    alert("executed");
  });
}
var FirstViewModel = function () {
  var self = this;
  self.array = ko.observableArray([]);
  self.push = function () {
    self.array.push(new SecondViewModel());
    alert("pushed");
  }
}

var SecondViewModel = function () {
  var self = this;
  self.z = ko.observable();
}

var mvm = new MasterViewModel();
ko.applyBindings(mvm);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
  <div data-bind="value: func">
     <div data-bind="with: nested">
       <button data-bind="text: 'push me', click: push"></button>
     </div>
  </div>
&#13;
&#13;
&#13;

请注意,现在,按下按钮时,仅显示"pushed"的警告。

答案 1 :(得分:0)

首先:<div data-bind="func">中的bindingName: boundValue为我举起了一面红旗。通常,绑定的格式为self.array

但是回答这个问题:只要计算出任何可观察到的可观察量,就会重新计算计算值。您正在更改FirstViewModel#push中的MasterViewModel,因此自然会重新计算在self.nested.array中使用它的计算值(作为NSDate *startDate = [NSDate date]; NSDate *endDate = [startDate dateByAddingTimeInterval:+7*24*60*60]; NSDateFormatter *df=[[NSDateFormatter alloc] init]; [df setDateFormat:@"yyyy-MM-dd hh:mm a"]; - (BOOL)validateDates:(NSDate*)startDate EndDate:(NSDate*)endDate{ NSComparisonResult dateCompareResutFinal = [startDate compare:endDate]; if (dateCompareResutFinal == NSOrderedDescending) { [RKDropdownAlert dismissAllAlert]; [RKDropdownAlert title:AlertNotificationError message:@"Start date should be less than End date" backgroundColor:[UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.7] textColor:[UIColor whiteColor] time:2 delegate:self] ; return NO; }else if (dateCompareResutFinal == NSOrderedSame) { [RKDropdownAlert dismissAllAlert]; [RKDropdownAlert title:AlertNotificationError message:@"Both dates cannot be same" backgroundColor:[UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.7] textColor:[UIColor whiteColor] time:2 delegate:self]; return NO; }else{ return YES; } } )。