6

给定以下 HTML/JS ( http://jsfiddle.net/mgs_jsfiddle/gUhm2/ )

<div data-bind="foreach: users">
    <p data-bind="click: $root.onClick">
        <span data-bind="text: id"></span>
        <span data-bind="text: firstName"></span>
        <span data-bind="text: $root.isSelected($data)"></span>
    </p>
</div>

$(function() {
    function ViewModel() {
        var self = this;
        self.users = [
            { id: 1, firstName: "Bob" },
            { id: 2, firstName: "David" },
            { id: 3, firstName: "Walter" }
            ];
        self.selectedId = ko.observable(1);
        self.isSelected = function(user) {
            return user.id === self.selectedId() ? "YES" : "NO";
        };
        self.onClick = function(user) {
            self.selectedId(user.id);
        }
    };
    ko.applyBindings(new ViewModel());
});

显示一个列表。通过单击一行,该行的 id 存储到selectedId.

我不明白,为什么在更改isSelected时重新评估功能。selectedId毕竟,这不是计算出来的。为什么还要重新评估?

4

2 回答 2

6

发生这种情况是因为isSelected()方法访问selectedId属性(即observable)。考虑一下:

HTML

<!-- adding into the foreach: block  -->
<span data-bind="text: $root.someFunc()"></span>
<span data-bind="text: $root.someOtherFunc()"></span>

JS

// adding to a model definition
self.someFunc = function() {
    self.selectedId();
    console.log('I AM AN OBSERVER');
    return 'oi: ' + Math.random();
};
self.someOtherFunc = function() {
    // self.selectedId();
    console.log('AND I AM NOT');
    return 'no: ' + Math.random();
}

小提琴

如您所见,这些函数之间的唯一区别是第一个确实检查定义为的模型属性的值ko.observable。因此,每次self.selectedId更改时,都会通知此函数(这实际上意味着它的重新运行)。

请注意,如果您删除了相应的data-bind部分,该方法将不会在视图初始化阶段运行,因此无法注册为适当的观察者。

第二种方法虽然也在初始化阶段被调用,但不会尝试检查selectedId值 - 所以它没有注册为这个值的观察者,并且随后也没有被调用。

于 2013-09-13T16:48:53.517 回答
1

Knockout 使用计算的 observables 来更新绑定。它是这样的(从bindingAttributeSyntax.js修改):

ko.computed({
    read: function() {
        bindingHandler.update(node, getValueAccessor(bindingKey), allBindings,
            bindingContext.$data, bindingContext);
    },
    disposeWhenNodeIsRemoved: node
});

因此,您访问以获取绑定值的任何可观察对象都将成为此计算的可观察对象的依赖项并导致绑定更新。

于 2013-09-13T20:58:35.533 回答