【问题标题】:How to raise an event after knockout rendering is complete?淘汰赛渲染完成后如何引发事件?
【发布时间】:2014-05-25 16:00:40
【问题描述】:

这个 jquery 移动表正在被淘汰。

<table data-role="table" id="report-table" class="ui-body-a ui-shadow ui-responsive table-stripe"
    data-column-btn-theme="a" data-column-btn-text="Spalten..." data-column-popup-theme="a" data-mode="columntoggle"">
    <thead>
        <tr data-bind="foreach: columns">
            <th data-bind="text: $data.Caption, attr: { 'data-priority': 1 + Math.floor($index() / 4) }"></th>
        </tr>
    </thead>
    <tbody data-bind="foreach: { data: rows, afterRender: tableRowAfterRender }">
        <tr data-bind="foreach: $parent.columns">
            <!-- ko template: { name: $data.template } -->
            <!-- /ko -->
        </tr>
    </tbody>
</table>

为了让“columntoggle”真正起作用,我目前使用“aferRender”事件:

self.tableRowAfterRender = function (element, data) {
    // Skip unless data.Items()[i] is not the last element in the rows collections
    for (var i = 0; i < data.Items().length - 1; i++) {
        if (data.Items()[i] !== self.rows()[self.rows().length - 1].Items()[i])
            return;
    }

    // refresh table after 100ms delay
    setTimeout(function () { $("#report-table").table("refresh"); }, 100);
}

这很不稳定,我讨厌 setTimeout() 做事的方式,这种情况在我使用 jquery mobile 和淘汰赛时变得很常见。一旦所有的淘汰赛渲染或理想情况下与表格元素内的元素相关的所有渲染完成后,我需要一种强大的方法来引发事件。在某些此类情况下,我能够使用自定义绑定,但我不知道如何在此处执行此操作。

【问题讨论】:

标签: jquery-mobile knockout.js


【解决方案1】:

试试这个。用:&lt;div data-bind='template: { afterRender: myPostProcessingLogic }'&gt;. 包裹表格然后在 myPostProsssingLogic 中执行您需要执行的任何操作。但是,这只会在第一次呈现表格时调用。这是fiddle

 <div data-bind='template: { afterRender: myPostProcessingLogic }'> 
<table data-role="table" id="report-table" class="ui-body-a ui-shadow ui-responsive table-stripe"
    data-column-btn-theme="a" data-column-btn-text="Spalten..." data-column-popup-theme="a" data-mode="columntoggle"">
    <thead>
        <tr data-bind="foreach: columns">
            <th data-bind="text: $data.Caption, attr: { 'data-priority': 1 + Math.floor($index() / 4) }"></th>
        </tr>
    </thead>
    <tbody data-bind="foreach: { data: rows, afterRender: tableRowAfterRender }">
        <tr data-bind="foreach: $parent.columns">
            <!-- ko template: { name: $data.template } -->
            <!-- /ko -->
        </tr>
    </tbody>
</table>

【讨论】:

  • 谢谢,“myPostProcessingLogic”像你提到的那样运行一次,但每次呈现新表时我都需要运行“刷新”。当它最初呈现时,它是空的,没有列和行,jQuery Mobile 无法增强它。因此,至少每次动态添加列时,都需要运行“myPostProcessingLogic”,因此这种方法不适用于我的情况。
  • 当你说“每次渲染一个新表”时,你是替换整个表还是简单地添加/删除行?
  • 通常(它是一个单页应用程序)表格会获得一组不同的列和行。
  • 在这种情况下,我认为对我的模板有一个简单的修改,我认为这对你有用:添加数据:绑定到模板,只要绑定更改,模板就会重新生成,然后 myPostProcessingLogic 将再次运行。这是更新的fiddle。请注意,您需要使用
    包装内部 html。要对其进行测试,请使用结果窗格中的“高级选项”。在您的代码中,您不需要替换数组中的所有行和列,而是需要新建新数组并分配给 observable
  • 我添加了数据绑定,但在我的场景中似乎不起作用。 “刷新”总是在表格呈现之前被调用。我注意到,如果您在小提琴中添加新行,警报也会在该行被呈现之前显示。但是您小提琴中的其他操作似乎首先呈现并显示警报 - 根据需要。似乎很难预测 ko 何时渲染什么。
【解决方案2】:

你可以尝试使用绑定init

ko.bindingHandlers.init = {
    init: function(element, valueAccessor, allBindings, viewModel) {
        var action = valueAccessor();
        if (typeof action === 'function') {
            setTimeout(action.bind(viewModel, element), 0);
        }
    }
};

像这样:

ko.components.register('simple-component', {
    viewModel: function(params) {        
        this.title = params.title;
        this.initHandler = function() {
            console.log('DOM of component has been built.');
        };
    },
    template:
        '<div data-bind="init: initHandler">\
            Title is: <span data-bind="text: title"></span>\
        </div>'
});

这里有更复杂案例的信息 - http://blog.atott.ru/2015/08/dom-built-event-for-knockout-components.html

【讨论】:

    【解决方案3】:

    有一种简单的方法。这是过程

    为你的行分配一个类

    <tr class="row" data-bind="foreach: $parent.columns">
    

    使用 if 条件检查你的函数

    if(data.Items().length == $('row').length){
        $("#report-table").table("refresh")
    }
    

    或者手动调用任何事件

    $('#report-table').trigger('click')
    

    希望对你有帮助。

    编辑:

    创建一个新的 observable 并将其设置为 false。

    self.EnableTimeOut = ko.observable(false)
    

    现在根据您的要求将其设置为 true。这只是一个例子

    if(data.Items().length == $('row').length && data.Items().length > 0){
        self.EnableTimeOut(true)
        $("#report-table").table("refresh")
    }
    

    最后

    把它包起来

    setTimeout(function () { 
        if(self.EnableTimeOut()){
            $("#report-table").table("refresh"); 
        }
    }, 100);
    

    【讨论】:

    • 谢谢,这简化了对象比较(我不确定它是否会更快,因为它需要更多的 DOM 比较作为回报)。但是,"setTimeout" 仍然是必需的,如果我在没有 setTimeout 的情况下执行 table("refresh"),则为时过早,表格尚未准备好刷新,jQuery 增强功能无法完全发挥作用。
    • 为此,您可以使用旗帜。将新的 observable 设置为 false。当它第一次运行时,使它成为真的。然后,当调用设置超时使用条件时,只有当它设置为真时才运行。
    • 您是否添加了“EnableTimeOut”以确保刷新只运行一次?我的问题不是我不能只运行一次刷新,而是我的问题是,当行和列被渲染时,我不知道刷新的方法。在敲除渲染列和行之后,我必须调用 ´$("#report-table").table("refresh")´。
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签