Knockout模板:afterRender触发两次,因为名称/数据是可观察的

时间:2013-11-19 22:34:44

标签: javascript templates knockout.js

我无法让afterRender触发一次。我看到afterRender被触发两次,因为我的模板绑定中有两个observable同时更新:

<div data-bind="template: { name: template.name(), data: template.data, if: template.data, afterRender: doSomeStuff }">
</div>

这是因为对name的更新会触发对data的更新,因为它是一个计算的observable,其值取决于名称:

this.data = ko.computed({
    var viewName = this.name();
    switch (viewName) {
        case "a":
            return this.modelA();
        case "b":
            return this.modelB();
        case "c":
            return this.modelC();
        default:
            return null;
    }
});

我要做的是记录模板渲染的时间。我还担心渲染两次可能会对性能产生影响 - 模板中的那些DOM元素是每次name更改一次创建的两次吗?

可能data更改(例如,modelA,modelB或modelC对象更改)而name没有更改,我希望data更改为afterRender触发afterRender,如果它自己更改。理想情况下,我可以将名称数据更新结合到触发deferEvaluation一次,但我不确定这是否可行。

有没有一种优雅的方法来实现这一目标?

  • 我调查了油门延长器,但那些不会阻止油门延长器 模板绑定被触发两次
  • data关于 template.name计算的observable似乎不会导致模板 data更改时绑定以获取新对象(不是 确定这是因为模板绑定实际上并非如此 在template.name更改时重新评估with,并且仍应触发模板绑定两次。

我正在考虑完全摆脱数据对象,并在每个HTML模板中,将{{1}}绑定直接附加到modelA,modelB和modelC,但是如果是的话我不会得到那些afterRender更新数据变化。

编辑:我正在使用KO 2.2.1,并意识到模板名称不可观察(直到2.3.0),因此在template.name之后的括号。所以我最初假设这个afterRender发生两次因为名字是一个可观察的也必须是不正确的?

1 个答案:

答案 0 :(得分:2)

使用计算的observable更新绑定,该observable跟踪对任何依赖项的更改。您的情况是这样的:计算C(template绑定)依赖于计算B(data)和可观察A(name),计算B依赖于可观察A。当A更改,它更新B和C.当B更新时,它也会更新C.所以这就是C获得两次更新的原因。

作为参考,这里是jsFiddle中的示例,显示了两个更新:http://jsfiddle.net/mbest/DnY9V/

节气门延长器

Knockout的节流扩展器是防止多次更新的唯一内置方法。您可以创建一个自定义绑定,它包装模板绑定以在受限制的计算可观察对象中运行更新。

ko.bindingHandlers.throttledTemplate = {
    init: function(element) {
        var args = arguments, self = this,
            result = ko.bindingHandlers.template.init.apply(this, arguments);
        ko.computed(function() {
            ko.bindingHandlers.template.update.apply(self, args);
        }, null, {disposeWhenNodeIsRemoved: element}).extend({throttle:1});

        return result;
    }
};

http://jsfiddle.net/mbest/j5D6p/

延迟更新插件

或者,您可以使用我的Deferred Updates插件来阻止对计算的可观察量的所有重复更新:https://github.com/mbest/knockout-deferred-updates

http://jsfiddle.net/mbest/UXYJx/