使用 Knockout 绑定到 return 字符串

Using Knockout bindings to return string

我正在尝试使用 Knockout 来更好地使用我正在使用的无限滚动插件,但在如何绑定它方面遇到了困难。不确定以当前形式是否可行。

滚动条调用一个数据函数,该函数通过 AJAX 加载下一个数据块。然后它调用一个工厂函数将该数据转换为 HTML,然后将 HTML 加载到容器中,并根据当前内容大小更新其内部状态。

我坚持认为它需要一个 HTML 字符串。

我想做的是:

<div class="scroller" data-bind="infiniteScroll: { get: loadItems }">
    <div class="item">
        <p>
            <span data-bind="text:page"></span>
            <span class="info" data-bind="text"></span>
        </p>
    </div>
</div>

我完全坚持的绑定是这个 - 目前只是对响应进行硬编码,显然 - 这是我需要用模板绑定替换的部分:

ko.bindingHandlers.infiniteScroll = {
    init: 
        function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext) 
        {
            if($.fn.infiniteScroll)
            {
                // Get current value of supplied value
                var field = f_valueaccessor();
                var val = ko.unwrap(field);

                var options = {};

                if(typeof(val.get) == 'function')
                    options = val;
                else
                    options.get = val;

                options.elementFactory = options.elementFactory || 
                    function(contentdata, obj, config)
                    {
                        var s = '';

                        for(var i = 0; i < contentdata.length; i++)                         
                        {
                            var o = contentdata[i];

                            // NEED TO REPLACE THIS
                            s += '<div class="item"><p>Item ' + o.page + '.' + i + ' <span class="info">' + o.text + '</span></p></div>';
                        }

                        return s;
                    };

                $(el).infiniteScroll(options);

                return { controlsDescendantBindings: true };
            }
        }
};

contentdata 是一个对象数组,例如[ { page:1, text:'Item1' }, { page:1, text:'Item2' } ... ]

调用之间的页面大小可能不同;我无法知道该服务将 return;它不是传统的页面,更像是下一个数据块。

所以在元素工厂中,我想以某种方式使用 .scroller 中的标记作为模板绑定 contentdata 数组,类似于 foreach,然后 return 该标记到滚动条插件。

请注意,我可以修改无限滚动源,所以如果不能用字符串完成,returning DOM 元素也可以。

我只是不知道如何 a) 使用内容作为模板,以及 b) return 将绑定结果绑定到插件以便它可以更新其状态。

注意:我最终打算使用的页面目前正在使用 foreach 非平凡对象模型;因此需要使用相同的标记;它需要大量更换。

在这个问题之后,我实际上已经找到了如何使用现有的滚动条来做到这一点:Jquery knockout: Render template in-memory

基本上,您使用 applyBindingsToNode(domelement, bindings),这会将 KO 绑定应用于节点集,重要的是不必连接到 DOM。

所以我可以将绑定元素中的标记存储为模板,然后将其清空,然后为元素工厂使用 jQuery 创建一个临时节点集,使用上述函数绑定它,然后 return HTML.

诚然,重构为使用纯 KO 滚动条可能会更好,但这意味着我可以继续使用经过测试和熟悉的插件,代码可能会对人们有所帮助,因为这似乎是一个很常见的问题主题。

这是绑定的新代码(标记如上)。

ko.bindingHandlers.infiniteScroll = {
    init: 
        function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext) 
        {
            if($.fn.infiniteScroll)
            {
                // Get current value of supplied value
                var field = f_valueaccessor();
                var val = ko.unwrap(field);

                var options = {};

                if(typeof(val.get) == 'function')
                    options = val;
                else
                    options.get = val;

                var template = $(el).html();

                options.elementFactory = options.elementFactory || 
                    function(contentdata, obj, config)
                    {
                        // Need a root element for foreach to use as a container, as it removes the root element on binding.
                        var newnodes = $('<div>' + template + '</div>');

                        ko.applyBindingsToNode(newnodes[0], { foreach: contentdata });

                        return newnodes.html();                         
                    };

                $(el)
                    .empty()                
                    .infiniteScroll(options);

                return { controlsDescendantBindings: true };
            }
        }
};