我试图使用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' } ... ]
不同来电之间的网页尺寸可能不同;我无法知道服务会返回什么;它不是传统的页面,更多地将其视为下一个数据块。
所以在元素工厂中我想以某种方式使用.scroller
中的标记作为模板绑定contentdata数组,类似于foreach,然后将该标记返回到滚动插件。
请注意,我可以修改无限卷轴源,所以如果不能用字符串完成,返回DOM元素也没问题。
我只是不知道如何a)将内容用作模板,b)将绑定结果返回给插件,以便更新其状态。
注意:我最终打算使用它的页面目前在非平凡对象模型上使用foreach
;因此需要使用相同的标记;它需要几乎是替代品。
答案 0 :(得分:0)
我实际上已经知道如何使用现有的滚动条来完成这个问题:Jquery knockout: Render template in-memory
基本上,您使用applyBindingsToNode(domelement, bindings)
,它将KO绑定应用于节点集,重要的是不必连接到DOM。
所以我可以将绑定元素的标记存储为模板,然后将其清空,然后对于元素工厂,使用jQuery创建临时节点集,使用上面的函数绑定它,然后返回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 };
}
}
};