我正在尝试使用knockoutjs foreach绑定指定插入元素的入口效果。设置非常简单:
myViewModel.myObservableArray.push({enter:function() { ... });
并在标记中:
foreach:{data:myObservableArray, afterRender:enter}
好像应该有用......对吗?但它没有在项目上找到输入功能。我发现的工作是:
myViewModel.enter = function(something, item) { item.enter(); };
foreach:{data:myObservableArray, afterRender:$root.enter}
将enter函数添加到根视图模型并将afterRender
绑定到$ root.enter。然后输入作为第二个参数传递给项目,因此可以依次调用项目的输入功能,但感觉就像是黑客。
有谁能解释这里发生了什么?
感谢。
修改
澄清我已经创建了fiddle。
这样做非常简单,并且在animated transitions example中有更深入的介绍。它在根视图模型中为使用foreach绑定插入的每个dom元素运行一个函数。
所以问题是:如果我想要特定于项目的afterRender,afterAdd或beforeRemove函数怎么办?我可以看到这很有用。特别是如果使用模板绑定来动态选择模板(note 4)。这样做有干净的方法吗?现在我在视图模型的根目录中有一个enter
函数,它只是调用项目上的enter
函数,但就像我上面说的那样,感觉就像是一个黑客。
答案 0 :(得分:5)
不,这就是it was designed的方式。
来自Documenation:
注3:使用“afterRender”,“afterAdd”和“beforeRemove”
有时您可能希望在模板生成的DOM元素上运行自定义后处理逻辑。例如,如果您正在使用JavaScript小部件库(如jQuery UI),则可能需要拦截模板的输出,以便您可以在其上运行jQuery UI命令,将某些呈现的元素转换为日期选择器,滑块或还要别的吗。
通常,对DOM元素执行此类后处理的最佳方法是编写custom binding,但如果您真的只想访问模板发出的原始DOM元素,则可以使用afterRender。 / p>
传递一个函数引用(函数文字,或者给视图模型上的函数名称),Knockout将在渲染或重新渲染模板后立即调用它。
(强调我的)
正如它所说,自定义绑定是另一种方法,可能会更好,具体取决于enter()
函数的作用。
答案 1 :(得分:5)
下划线去抖(_.debounce)是一个很好的解决方案。
模板
data-bind=" template: {foreach:myObservableArray, afterRender: runWhenAllRenderDone }
如果在最后100毫秒内未触发afterRender,则会执行去抖功能。
var runWhenAllRenderDone = _.debounce(myFunction, 100);
function myFunction(){
//do some task but do it for once only
}
不是很棒吗?
答案 2 :(得分:0)
找到了另一种没有timeout
的解决方法,该技术基于虚拟元素<!-- ko if: $parent.afterRender($index()) --><!-- /ko -->
function ReservationsViewModel() {
// Editable data
this.seats = ko.observableArray([
{ name: "Steve", meal: "Standard (sandwich)", price: 343},
{ name: "Steve", meal: "Premium (lobster)", price: 10},
{ name: "Steve", meal: "Ultimate (whole zebra)", price: 290}
]);
this.afterRender = (i) => {
// checking element rendered is last
if (i === this.seats().length - 1) {
console.log('rendered');
// our after rendered logic goes here...
}
};
}
它的模板是
<tbody data-bind="foreach: seats">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: meal"></td>
<td data-bind="text: price"></td>
</tr>
<!-- ko if: $parent.afterRender($index()) --><!-- /ko -->
</tbody>
这个额外的逻辑i === this.seats().length - 1
,将检查是否渲染了最后一行。然后我们可以在内部执行afterRender逻辑。