当所有嵌套组件都被渲染时,KnockoutJS afterRender回调?

时间:2014-11-26 19:27:46

标签: javascript knockout.js knockout-components

我有一个使用3.2.0的嵌套KnockoutJS组件的层次结构。它工作得很好但是我希望在加载和渲染整个组件层次结构后执行一些代码。它与afterRender()大致相当,与afterRender相同的常见用例需要。

到目前为止,我尝试了一些方法,但没有运气:

  1. 在根模板中添加了以下内容,但在嵌套组件加载之前调用它,所以太早了。 <!--ko template: {afterRender: onLoad.bind($data)} -->
  2. 使用最新的3.3.0-alpha并在所有组件上指定synchronous:true。但我相信,因为我使用AMD,所以组件仍然是异步“加载”,这意味着仅仅因为我的root applyBindings()返回,并不意味着所有组件都已加载和呈现。
  3. 甚至尝试构建一个只在加载相应组件时才能解析的延迟对象集合。这变得过于复杂,但由于我不愿意这样做而仍然无效。
  4. 一旦加载并渲染了knockoutjs组件的完整层次结构,是否有办法获得回调?谢谢!

    我刚刚遇到这两个线程,所以似乎其他人也在寻找这个。与现有解决方法的关键区别在于它们不适用于嵌套组件。

3 个答案:

答案 0 :(得分:3)

我写了一个淘汰库,当所有组件都已加载并绑定时触发事件。它使用引用计数,类似于用于垃圾收集的引用计数。我在我的项目中广泛使用组件,包括嵌套很多层次,我不能不知道什么时候“准备就绪”。我没有花太多时间在使用文档上,但基础知识就在那里。

Git Hub维基: https://github.com/ericraider33/ko.component.loader/wiki

小提琴: https://jsfiddle.net/ericeschenbach/487hp5zf/embedded/result/

用法HTML:

<div id="ko-div">
  Status: <span data-bind="text: loading() ? 'Loading' : 'Done'"></span>
  <br><br>
  <test-panel></test-panel>
</div>

用法JS:

var pageModel = { 
  loading: ko.observable(true), 
    completedCallback: function (childRef) { 
    pageModel.loading(false); 
    childRef.testValue(childRef.testValue()+1);  
  }
};

var tpRef = ko.componentLoader.ref.child({ completedCallback: pageModel.completedCallback});
var tpModel = { 
  attached: function(element) { return tpRef; },
  testValue: ko.observable(5)
};

ko.components.register('test-panel', {
    viewModel: function() { return tpModel; },
    template: '<div data-bind="attached: true">Test Panel<br>From Code <span data-bind="text: testValue"></span></div>'
});


ko.componentLoader.setOptions({ verbose: true });
ko.applyBindings(pageModel, $('#ko-div')[0]);

答案 1 :(得分:2)

这对我有用。我没有在所有可能的变体中尝试它,例如混合同步和异步组件,或使用自定义组件加载器。

KO 3.3.0中有一个方法,所有组件加载都通过:

ko.components = { get: function(componentName, callback) { ...

使用所需的get调用componentName方法,并在加载组件时调用callback

所以你需要做的就是在每次调用时包装ko.components.getcallback并增加pendingComponentsCount,并在callback执行后减少它。当计数达到零时,表示所有组件都已加载。

25行JS代码(使用underscorejs)。

您还需要处理ko.applyBindings没有遇到任何组件的特殊情况,其中也意味着所有组件(全部为零)都已加载。

同样,不确定这是否适用于所有情况,但它似乎在我的情况下工作。我可以想到几个可以轻易破解的场景(例如,如果有人在你将其包装之前缓存对ko.components.get的引用)。

答案 2 :(得分:1)

如果你使用ko.components这可能有用:

1)创建一个延迟对象来跟踪每个组件的加载

var statusX = $.Deferred()
var statusY = $.Deferred()

2)通知淘汰赛告诉您组件何时加载并准备就绪

ko.components.get('x-component', statusX.resolve) //Note: not calling resolve, but passing the function
ko.components.get('y-component', statusY.resolve)

3)同步两个状态延期

$.when(statusX.promise(), statusY.promise())
 .done( function allComponentsLoaded(componentX, componentY){ 
            //Both components are ready here 
            //Note the arguments from the function comes via
            //ko->jquery deferred resolve
           });