【问题标题】:KnockoutJS afterRender callback when all nested Components have been rendered?渲染所有嵌套组件时,KnockoutJS afterRender 回调?
【发布时间】:2015-01-25 06:21:33
【问题描述】:

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

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

  1. 在根模板中添加了以下内容,但在加载嵌套组件之前调用它,为时过早。 <!--ko template: {afterRender: onLoad.bind($data)} -->
  2. 使用最新的 3.3.0-alpha 并在所有组件上指定 synchronous:true。但我相信,由于我使用的是 AMD,组件仍然是异步“加载”的,这意味着仅仅因为我的根 applyBindings() 返回,并不意味着所有组件都已加载和渲染。
  3. 甚至尝试构建延迟对象的集合,这些延迟对象仅在加载相应组件时才被解析。这变得过于复杂,但由于我不会详细介绍的原因仍然无法正常工作。

有没有办法在加载和渲染完整的 knockoutjs 组件层次结构后调用回调?谢谢!

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

【问题讨论】:

  • 只是好奇,如果您为每个组件回显“xx 之前”和“xx 之后”,console.log 会是什么样子?尽管“之后”不能正常工作,嵌套组件可能会正确触发 before/etc 事件?这可用于手动跟踪流程何时完成。
  • 你试过这个... data: dataItems 将替换 foreach data-bind="template: { name: 'template-name', data: dataItems, afterRender: callbackmethod}"

标签: javascript knockout.js knockout-components


【解决方案1】:

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

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]);

【讨论】:

  • 感谢一个不错的插件。不过有一个问题,为什么它在你的小提琴中说Component not found. Ignoring attached event for component object
  • 我已更新插件以跳过该警告。对于我的项目,我使用 RequireJS,并且该插件有一些方便的方法来设置 require。您看到的警告仅与该设置相关。感谢您指出这一点。
  • 我明白了。当我看到这条消息时,我有点担心我误用了它:) 感谢您的详细说明
【解决方案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 的引用)。

【讨论】:

    【解决方案3】:

    如果您正在使用 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
               });
    

    【讨论】:

    • a) 这是一种解决方法,但它并不漂亮(我想这几乎就是第 3 点的内容)b) 如果不是,它会强制加载一个组件(这可能不是你想要的其实想要)
    • 非常适合我的需要。如果组件也被标记为同步渲染,则很有帮助。因此,我可以使用回调等到至少通过 requireJS 获取了 HTML(仅在第一次发生),然后依靠同步渲染来确保在我访问元素时 HTML 存在于我的文档中。在我的情况下,我需要向组件的绑定元素添加一个额外的子节点,这最初无法正常工作,因为 KO 在应用组件绑定时清除了所有子节点。
    猜你喜欢
    • 2016-06-20
    • 1970-01-01
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多