与对您的问题的评论中给出的解决方案相反,我建议您不要在 viewmodel 方法中混合 DOM 处理和 ViewModel 功能。一般来说,我建议避免做任何使视图模型依赖于 DOM 的事情。
当谈到 foreach-binding 的动画时,我首先建议创建一个自定义 bindingHandler ,它实际上会使用 foreach-binding 并添加你想要的动画。这样,您可以将与 DOM 相关的代码保留在视图或 bindingHandlers 中,它们应该在哪里。
在某些情况下,您可能不想为其创建自定义绑定,而只是希望动画方法可用于您的 foreach 绑定。在这些情况下,将这些方法放在视图模型上可能是一种更实用的方法。但是,如果您这样做,我建议您完全避免让您的视图模型功能依赖于这些方法,只保留它们用于执行 DOM 动画逻辑。
鉴于这种方法,您的视图模型可能看起来类似于(复制小提琴中的视图模型,然后添加动画方法):
function ViewModel() {
var self = this;
self.selectedCategory = ko.observable("");
self.setCategory = function (newCat) {
self.selectedCategory(newCat);
};
self.allCharities = ko.observableArray([
new Charity(0, "Amnesty International", "$2,466", "HUMANITARIAN"),
new Charity(1, "Richard Dawkins Foundation", "$0", "EDUCATION"),
new Charity(2, "Khaaaan Academy", "13,859", "EDUCATION"),
new Charity(4, "Wikipedia", "$7,239", "EDUCATION")
]);
self.filteredCharities = ko.computed(function () {
// If no category is selected, return all charities
if (!self.selectedCategory())
return self.allCharities();
// Return charities in the selected category
return ko.utils.arrayFilter(self.allCharities(), function (c) {
return (c.Category() == self.selectedCategory());
});
}, this);
var fadeAnimationDuration = 500;
self.animationAfterAddingCharityElementsToDom = function(element){
//Since this method will be depending on the DOM, avoid having
//the viewmodel functionality depending on this method
//First hide the new element
var $categoryDomElement = $(element);
$categoryDomElement.hide();
var $tabDomElement = $categoryDomElement.parent();
$tabDomElement.fadeOut(fadeAnimationDuration, function(){
//When the tab has faded out, show the new element and then fade the tab back in
$categoryDomElement.show();
$tabDomElement.fadeIn(fadeAnimationDuration);
});
};
self.animationBeforeRemovingCharityElementsFromDom = function(element){
//Since this method will be depending on the DOM, avoid having
//the viewmodel functionality depending on this method
var $categoryDomElement = $(element);
var $tabDomElement = $categoryDomElement.parent();
$tabDomElement.fadeOut(fadeAnimationDuration, function(){
//When the tab has faded out, remove the element and then fade the tab back in
$categoryDomElement.remove();
$tabDomElement.fadeIn(fadeAnimationDuration);
});
};
};
然后您的绑定将是:
<div class="tab" data-bind="foreach: { data: filteredCharities, afterAdd: animationAfterAddingCharityElementsToDom, beforeRemove: animationBeforeRemovingCharityElementsFromDom }">
<div class="tab-tile mb21" data-bind="css:{'mr21':$index()%3 < 2}">
<a href="#" class="amount" data-bind="text: Amount"></a>
<a href="#" class="title" data-bind="text: Name"></a>
<a href="#" class="category" data-bind="text: Category"></a>
</div>
</div>
我已经用上面的代码更新了你的小提琴,你可以在http://jsfiddle.net/LkqTU/23825/找到它。
如果您希望创建多个实例,那么将这些方法添加到 viewmodel 构造函数原型中也可能是一个好主意(并且更“正确”)。