Javascript 淘汰计算与订阅、时间问题

Javascript 淘汰计算与订阅、时间问题,javascript,knockout.js,Javascript,Knockout.js,刚刚发现,在KnockoutJS中,订阅函数是在依赖计算之前评估的,需要有人能够提交,因为我在文档或论坛中找不到任何关于Knockouts计时的信息 这意味着:如果我有一个这样的模型 var itemModel = function (i) { var self = this; self.Id = ko.observable(i.Id); self.Title = ko.observable(i.Title); self.State = ko.observabl

刚刚发现,在KnockoutJS中,订阅函数是在依赖计算之前评估的,需要有人能够提交,因为我在文档或论坛中找不到任何关于Knockouts计时的信息

这意味着:如果我有一个这样的模型

var itemModel = function (i) {
    var self = this;

    self.Id = ko.observable(i.Id);
    self.Title = ko.observable(i.Title);
    self.State = ko.observable(i.State);

};

var appModel = function () {
   var self = this;

   self.Items = ko.observableArray() // <-- some code initializes an Array of itemModels here
   self.indexOfSelectedItem = ko.observable();

   self.selectedItem = ko.computed(function () {
       if (self.indexOfSelectedItem() === undefined) {
            return null;
       }
       return self.Items()[self.indexOfSelectedItem()];
   });
};
appModel.indexOfSelectedItem.subscribe(function () {
    // Do something with appModel.selectedItem()
    alert(ko.toJSON(appModel.selectedItem()));
}
…在使用新的索引值重新计算计算值之前,将对订阅函数进行求值,因此我将获得对应于上一个选定索引而不是实际选定索引的selectedItem()

两个问题:

  • 是这样吗
  • 那么,如果一个简单的函数每次调用时都会得到当前选定的项,而ko.computed在任何时候都会得到求值,而所有事情都已经完成了,我不再需要它,那么我为什么要使用ko.computed()

默认情况下,敲除中的所有计算结果都是以急切的方式进行评估的,而不是以惰性的方式(即,不是在您第一次访问它们时)

一旦一个依赖项发生更改,将通知所有订阅,并重新评估所有连接的计算。您可以通过在计算的可观察对象中指定,将该行为更改为“懒惰”,但不能对订阅执行此操作

无论如何,我认为没有必要依赖于所选项目的索引。事实上,这甚至是一个糟糕的设计,因为你并不真正了解索引的数值,而是它所代表的项目

您可以通过创建一个可写的computed observable来反转依赖关系,该可写的computed observable为您提供当前所选项目的索引(出于diplay目的),并允许您更改它(为了方便)

函数AppModel(){
var self=这个;
self.Items=ko.observearray();
self.selectedItem=ko.observable();
self.indexOfSelectedItem=ko.computed({
读:函数(){
var i,
allItems=self.Items(),
selectedItem=self.selectedItem();
对于(i=0;i
Knockout支持存储/处理实际值,而不仅仅是值的索引,因此对视图进行必要的更改可能并不困难。只需将以前写入
indexOfSelectedItem
的所有内容直接写入
selectedItem
。对
selectedItem
的依赖项将继续正常工作

在设计良好的淘汰应用程序中,您很少需要处理数组项的索引。我建议在一切正常后,删除计算机的
写入
部分


请参阅:

为什么不在selectedItem上?因此
appModel.selectedItem.subscribe(函数(){
在这种情况下,当
selectedItem
发生更改时,将调用您的函数。顺便说一下,您的计算结果中有一个错误:
返回self.Items[self.indexOfSelectedItem()];
应该是
返回self.Items()[self.indexOfSelectedItem()];
注意额外的
()
因为不仅有一个依赖于索引的计算字段,还有更多。我需要一个处理程序,可以更新UI中的很多内容,所有这些计算字段也都已经更新。我现在应该订阅哪一个?我认为计算字段就像一个getter函数,在调用它时会进行计算。事实上有一段时间,这些都会绑定到一个旧的值,所以我认为最好使用简单的getter函数,不是吗?谢谢你关于额外的()的说法是正确的…谢谢,这真是一个伟大而有用的建议(实际上我不知道如何设计一个好的击倒应用程序)。我会这样做。我还需要索引是可写的,因为我将项目绑定到一个jquery ui accordion,其中accordion面板对应于数组索引。因此,如果我单击accordion面板来选择项目,除了设置appModel.indexOfSelectedItem()之外,我没有找到更好的方法来选择它到手风琴中的面板索引(面板不知道KO模型类).有更好的方法吗?我想有。我会试着想出一个更好的方法,等等。关键是要将视图、模型和绑定彼此分开。最干净的方法是将手风琴作为绑定声明的属性。例如,你可以声明意图“此元素应显示为手风琴,当前活动的面板应与所选项目相关联”。由于Knockout不了解手风琴,您可以为此创建自定义绑定,请参见此处:。(免责声明:这是一个例子。其他人已经为jQuery UI小部件创建了更完整的自定义绑定,请看一看。)啊,好吧。出于某种原因,fiddle拒绝在IE中运行。不过,它似乎是特定于JSFIDLE的。Firefox和Chrome工作得很好。这里有一个小小的扩展:它允许您动态绑定accorion选项(例如,
“禁用”
)到视图模型。
function AppModel() {
    var self = this;

    self.Items = ko.observableArray();
    self.selectedItem = ko.observable();

    self.indexOfSelectedItem = ko.computed({
        read: function () {
            var i,
                allItems = self.Items(),
                selectedItem = self.selectedItem();

            for (i = 0; i < allItems.length; i++) {
                if (allItems[i] === selectedItem) {
                    return i;
                }
            }
            return -1;
        },
        write: function (i) {
            var allItems = self.Items();

            self.selectedItem(allItems[i]);
        }
    });
}