javascript - 当 foreach 具有计算的可观察量时,动画过渡 beforeRemove/afterAdd

标签 javascript jquery knockout.js computed-observable

我在尝试使用 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/

相关文章:

javascript - 为什么 Node 不识别这个导入的函数?

javascript - 自动选中/取消选中 "All"复选框

javascript - knockout : Click button created server side

javascript - 事件有时似乎只触发?

javascript - 当 Knockout observable 未定义或禁用 JS 时显示默认值

javascript - HTML - 用户添加的变量

javascript - 使用原型(prototype)设置按钮的点击事件?

javascript - 光标位于文本框末尾时自动对焦

javascript - 如何使用javascript填充html表格而不使用div?

jquery - $(document).ready 在外部函数中调用?