我有一个viewModel
和一个根据if
条件呈现数据的模板:
<!-- ko template: { data: selectedFolder, if: isTemplateVisible, name: 'selectedFoldersProperties-template' } --><!-- /ko -->
我认为模板连续呈现4次,其中一个原因是isTemplateVisible
是ko.computed
。
如果我将if: isTemplateVisible
更改为if: selectedFolder
,则模板会连续呈现2次。
我有一个jsfiddle演示。
按下按钮后,您会看到“点击”输出4次。
为什么函数被调用了很多次?
<button id="button" type="button">
Set folder
</button>
<div>
<!-- ko template: { data: selectedFolder, if: isTemplateVisible, name: 'selectedFoldersProperties-template' } --><!-- /ko -->
</div>
<script type="text/html" id="selectedFoldersProperties-template">
<span data-bind="text: FolderName"></span>
<ul data-bind="foreach: $root.getFiles($data)">
<li>
<span data-bind="text: FileName"></span>
</li>
</ul>
</script>
var viewModel = {
selectedFolder: ko.observable(null),
getFiles: function(folderData) {
console.log("hit");
return [
{ FileName: "File 1" },
{ FileName: "File 2" }
];
}
};
viewModel.isTemplateVisible = ko.computed(function(){
return this.selectedFolder();
}, viewModel);
ko.applyBindings(viewModel);
document.getElementById("button").onclick = function() {
viewModel.selectedFolder({
FolderName: "Folder 1"
});
};
答案 0 :(得分:3)
您的isTemplateVisible
依赖于selectedFolder
,因此您可以重新渲染模板。
将isTemplateVisible
更改为不首先计算:
viewModel.isTemplateVisible = function(){
return this.selectedFolder();
};
然后更改模板上的if绑定以执行值out:
if: isTemplateVisible()
然后由于依赖性,你的tmeplate将不会运行两次。
<强>替代地强>
你可以通过删除iftemplateisvisible东西来简单地完成整个过程:
<button id="button" type="button">
Set folder
</button>
<div>
<!-- ko if: selectedFolder -->
<!-- ko template: { data: selectedFolder, name: 'selectedFoldersProperties-template' } --><!-- /ko -->
<!-- /ko -->
</div>
<script type="text/html" id="selectedFoldersProperties-template">
<span data-bind="text: FolderName"></span>
<ul data-bind="foreach: $root.getFiles($data)">
<li>
<span data-bind="text: FileName"></span>
</li>
</ul>
</script>
和viewmodel:
var viewModel = {
selectedFolder: ko.observable(null),
getFiles: function(folderData) {
console.log("hit");
return [
{ FileName: "File 1" },
{ FileName: "File 2" }
];
}
};
ko.applyBindings(viewModel);
document.getElementById("button").onclick = function() {
viewModel.selectedFolder({
FolderName: "Folder 1"
});
};
Here is fiddle for the second solution
进一步说明您遇到此问题的原因
所发生的事情是,在相同的注释绑定上,你有一个observable和一个相互依赖的计算器,因此它们会导致你的模板只渲染两次,只有一次。
所以你要么我建议需要在不同的绑定上分开它们,所以当你评估另一个时你已经解决了,或者你消除了其中一个。
如果您将绑定更改为不具有相互依赖性,例如:
if: selectedFolder(), data: selectedFolder
然后循环不会发生,因为你没有两件事彼此依赖并且负责渲染模板。
基于此,Throttle也不会帮助你,因为所有它都会延迟一个observable的值变化,这会延迟你的第一次渲染,然后是交叉引用引起的相互依赖循环。
getFiles函数由于是绑定上的自执行函数而运行两次。当它被放置在页面上时它会调整一次,而当轮到它在foreach中运行时它会再次调整。
This can be demonstrated here您可以在其中看到您的getFiles函数的调用者都是您模板中的function (){return $root.getFiles() }
。
如果在没有括号的情况下将该函数更改为foreach: $root.getFiles
并使getFiles成为observableArray,以便通过knockout解决它,那么您将不会遇到两次执行问题。
答案 1 :(得分:1)
那是因为你有foreach绑定。
此代码<ul data-bind="foreach: $root.getFiles($data)">
将导致计算4次。
希望明确