假设我们有如下数据
var data = {
facets: [{
name : "some name",
values: [{
value: "some value"
}]
}]
};
我们可以很容易地将其表示为绑定到敲除模板的视图模型,如下所示:
<ul data-bind="foreach: facets">
<li>
<span data-bind="text: name"></span>
<ul data-bind="foreach: values">
<li data-bind="text: value"></li>
</ul>
</li>
</ul>
问题是,在使用渐进式增强时,我们如何实现相同的结果?这是通过最初在服务器端呈现模板,然后将淘汰模板和视图模型绑定到该呈现来实现的。
一个简单的服务器端模板如下所示:
<ul>
<li>
<span>some name</span>
<ul>
<li>some value</li>
</ul>
</li>
</ul>
我探索了几种不同的可能性:
这两种方法似乎都不是很干净。另一种解决方案可能是编写一个自定义绑定来处理整个呈现过程,并在可能的情况下重用现有元素。
还有其他想法吗?
发布于 2012-01-28 21:29:47
我在这里探索了几种方法,包括从第一个元素生成匿名模板,如下所述:
http://groups.google.com/group/knockoutjs/browse_thread/thread/3896a640583763d7
或者通过自定义绑定为数组的每个元素创建单独的绑定,例如
ko.bindingHandlers.prerenderedArray = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
var binding = valueAccessor();
binding.firstTime = true;
$(element).children().each(function(index, node) {
var value = ko.utils.unwrapObservable(binding.value)[index];
ko.applyBindings(value, node);
});
return { 'controlsDescendantBindings': true };
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var binding = valueAccessor();
if (binding.firstTime) {
binding.firstTime = false;
return;
}
$(element).children().remove();
ko.applyBindingsToNode(element, { template: { name: binding.template, foreach: binding.value }}, viewModel)
}
};
它对每个元素应用特定的绑定,然后在第一次更新时将内容替换为普通的foreach绑定。这种方法仍然意味着您仍然需要两个模板。这两种方法还涉及通过服务器呈现的JSON初始化状态。
我选择使用的当前方法(尽管可能会有变化)是将所有的Knockout模板放在脚本标记中,这样它们就永远不会在NoJS浏览器中呈现出来。NoJS模板在服务器端呈现为div的内容。一旦Knockout模板被呈现,div的内容将被script标记中的Knockout模板替换。您可以用相同/相似的方式设置它们的样式,以实现无缝转换,如果不能这样做,则可以通过CSS隐藏noJS模板。
最后,我得出结论,Knockout.js和渐进式增强并不能很好地协同工作,应该选择另一种,即使用更传统的方法(如直接jQuery DOM操作)构建需要渐进式增强的应用程序的某些部分。
发布于 2012-01-22 20:35:36
只需在服务器端模板中添加各种data-
属性即可。如果JavaScript被禁用,它们不会受到影响,所以拥有它们根本不是问题。
发布于 2012-01-22 21:45:11
恐怕没有干净的方法可以做到这一点。就我个人而言,我在后端呈现页面,然后将完全相同的上下文数据传递到前端(序列化为JSON),并使用它设置Knockout。这意味着存在一些重复。也许将后端切换到node.js会简化这里的事情。
https://stackoverflow.com/questions/8961073
复制相似问题