我在尝试使用 jquery 动画时面临一些挑战,例如带有 knockout 的 fadeIn() fadeOut()。
实例,无动画:http://jsfiddle.net/LkqTU/23801/
我使用计算的可观察量来过滤我的原始慈善机构数组。计算结果与 foreach 进行数据绑定(bind),我想让整个容器(带有 .tab 类)在任何更改之前淡出,并在更改之后淡入。
我尝试使用内置的 beforeRemove 和 afterAdd 属性,但是在计算数组时这似乎不起作用。正如下面的实时示例所示,容器被一些慈善机构的多个实例填满,即使底层计算数组仅包含正确的实例。
实时示例,带有(失败)动画:http://jsfiddle.net/fy7au6x6/1/
关于如何控制动画计算变化的时间有什么建议吗?
这是两个数组,“所有慈善机构”和“按类别过滤的慈善机构”:
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);
最佳答案
与您的问题评论中给出的解决方案相反,我建议您不要在 viewmodel 方法中混合 DOM 处理和 ViewModel 功能。一般来说,我建议避免做任何使视图模型依赖于 DOM 的事情。
当谈到 foreach 绑定(bind)的动画时,我首先建议创建一个自定义的 bindingHandler,它实际上会使用 foreach 绑定(bind)并添加您想要的动画。这样,您可以将 DOM 相关代码保留在 View 或绑定(bind)处理程序中,它们应该在的位置。
在某些情况下,您可能不想为其创建自定义绑定(bind),而只是希望动画方法可用于 foreach 绑定(bind)。在这些情况下,将这些方法放在 View 模型上可能是一种更实用的方法。但是,如果您这样做,我建议您完全避免 View 模型功能依赖于这些方法,只需保留它们仅用于执行 DOM 动画逻辑。
采用这种方法,您的 View 模型可能看起来类似于(复制 fiddle 中的 View 模型,然后添加动画方法):
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);
});
};
};
然后你的绑定(bind)将是:
<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>
我已经用上面的代码更新了你的 fiddle ,你可以在 http://jsfiddle.net/LkqTU/23825/ 找到它。 .
如果您希望创建多个实例,那么将这些方法添加到 viewmodel 构造函数原型(prototype)中也可能是一个好主意(而且更“正确”)。
关于javascript - 当 foreach 具有计算的可观察量时,动画过渡 beforeRemove/afterAdd,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29730593/