javascript 在foreach绑定中knockoutjs afterRender函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11749212/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
knockoutjs afterRender function in foreach binding
提问by nicholas
I'm trying to specify an entrance effect on elements being inserted using a knockoutjs foreach binding. Very simple setup:
我试图指定对使用knockoutjs foreach 绑定插入的元素的入口效果。非常简单的设置:
myViewModel.myObservableArray.push({enter:function() { ... });
and in the markup:
并在标记中:
foreach:{data:myObservableArray, afterRender:enter}
seems like it should work... right? But it doesn't find the enter function on the item. What I've found does work is:
似乎它应该工作......对吧?但它没有在项目上找到回车功能。我发现有效的是:
myViewModel.enter = function(something, item) { item.enter(); };
foreach:{data:myObservableArray, afterRender:$root.enter}
adding an enter function to the root view model and binding afterRender
to $root.enter. Enter is then passed the item as its second param so can in turn call the item's enter function, but it feels like a hack.
向根视图模型添加一个 enter 函数并绑定afterRender
到 $root.enter。Enter 然后将项目作为其第二个参数传递,因此可以依次调用项目的 enter 函数,但感觉就像一个黑客。
Can anyone explain what's going on here?
谁能解释一下这里发生了什么?
Thanks.
谢谢。
EDIT:
编辑:
To clarify I've created a fiddle.
为了澄清,我创建了一个fiddle。
What this does is very simple, and is covered in more depth in the animated transitions example. It's running a function in the root view model for each dom element that's inserted using the foreach binding.
它的作用非常简单,在动画过渡示例中有更深入的介绍。它在根视图模型中为使用 foreach 绑定插入的每个 dom 元素运行一个函数。
So the question is: what if I want item specific afterRender, afterAdd or beforeRemove functions? I could see this being useful. Especially if using the template binding to dynamically select a template (note 4). Is there a clean way of doing this? Right now I've got an enter
function in the view model's root that simply calls the enter
function on the item, but like I said above this feels like a hack.
所以问题是:如果我想要特定于项目的 afterRender、afterAdd 或 beforeRemove 函数怎么办?我可以看到这很有用。特别是如果使用模板绑定来动态选择模板(注 4)。有没有一种干净的方法来做到这一点?现在我enter
在视图模型的根中有一个函数,它只是调用enter
项目上的函数,但就像我上面说的那样,这感觉就像一个黑客。
回答by Kyeotic
Nope, this is the way it was designed.
不,这就是它的设计方式。
From the Documenation:
从文档:
Note 3: Using “afterRender”, “afterAdd”, and “beforeRemove”
Sometimes you might want to run custom post-processing logic on the DOM elements generated by your templates. For example, if you're using a JavaScript widgets library such as jQuery UI, you might want to intercept your templates' output so that you can run jQuery UI commands on it to transform some of the rendered elements into date pickers, sliders, or anything else.
Generally, the best way to perform such post-processing on DOM elements is to write a custom binding, but if you really just want to access the raw DOM elements emitted by a template, you can use afterRender.
Pass a function reference (either a function literal, or give the name of a function on your view model), and Knockout will invoke it immediately after rendering or re-rendering your template.
注 3:使用“afterRender”、“afterAdd”和“beforeRemove”
有时您可能希望在模板生成的 DOM 元素上运行自定义后处理逻辑。例如,如果您使用 JavaScript 小部件库(如 jQuery UI),您可能希望拦截模板的输出,以便您可以在其上运行 jQuery UI 命令,将一些呈现的元素转换为日期选择器、滑块或还要别的吗。
通常,对 DOM 元素执行此类后处理的最佳方法是编写自定义绑定,但如果您真的只想访问模板发出的原始 DOM 元素,则可以使用 afterRender。
传递函数引用(函数文本,或在视图模型上给出函数的名称),Knockout 将在渲染或重新渲染模板后立即调用它。
(Emphasis mine)
(强调我的)
As it says, a custom binding is another way to do it, and may be better depending on what that enter()
function does.
正如它所说,自定义绑定是另一种方法,并且可能会更好,具体取决于该enter()
函数的作用。
回答by Jhankar Mahbub
underscore debounce (_.debounce) is a great solution in such case.
在这种情况下,下划线去抖动 (_.debounce) 是一个很好的解决方案。
template
模板
data-bind=" template: {foreach:myObservableArray, afterRender: runWhenAllRenderDone }
debounce function will be executed if afterRender is not fired in last 100 milisecond.
如果 afterRender 在过去 100 毫秒内未触发,则将执行去抖动功能。
var runWhenAllRenderDone = _.debounce(myFunction, 100);
function myFunction(){
//do some task but do it for once only
}
is't it awesome?
是不是很棒?
回答by rab
Found another workaround without timeout
, this technique is based on virtual element <!-- ko if: $parent.afterRender($index()) --><!-- /ko -->
找到了另一种解决方法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...
}
};
}
And it's template is
它的模板是
<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>
This extra logic i === this.seats().length - 1
, will check last row is rendered.. then we can execute our afterRender logic inside.
这个额外的逻辑i === this.seats().length - 1
,将检查最后一行被渲染......然后我们可以在里面执行我们的 afterRender 逻辑。