33

我在淘汰 js 并将可观察数组显示为列表时遇到问题;在 beforeRemove 动画运行时添加项目时,被移除的元素会移动到列表的底部,而不是停留在其位置,直到动画完成并移除元素。

这是一个更好地解释问题的jsfiddle:http: //jsfiddle.net/bPP5Q/8/

有谁知道我怎么能解决这个问题?

javascript:

jQuery(function ($) {
    var ViewModel = function (data) {
        var self = this;
        self.data = ko.observableArray(data);
        self.removeLine = function (elem) {
            if (elem.nodeType === 1) $(elem).fadeOut(3000, function () {
                $(elem).remove();
            });
        }

        self.addLine = function (elem) {
            if (elem.nodeType === 1) 
                $(elem).hide().fadeIn(3000);
        }

        self.removeItem = function() {
            self.data.remove(function(item) { return item.test && item.test == 2; });   
        }

        self.addItem = function() {
            self.data.splice(1, 0, { test: 9 }); 
        }

        self.addremove = function () {
            self.removeItem();
            var id = setInterval(function() {
                self.addItem();
                clearInterval(id);
            },1000);
        }
    }

    var vm = new ViewModel([{ test: 9 }, { test: 2 }, { test: 1 }, { test: 1 }, { test: 1 }, { test: 1 }, { test: 1 }]);

    ko.applyBindings(vm);
});

HTML:

<button id="button" data-bind="click: addremove">Click</button>
<table id="grid">
    <tbody data-bind='template: { foreach: data, afterAdd: addLine, beforeRemove: removeLine }'>
        <tr>
            <td data-bind="text: test"></td>
            <td>

            </td>
        </tr>
    </tbody>
</table>
4

7 回答 7

1

您的函数“addItem”在 1 秒(setInterval 1000 毫秒)后执行,因此“self.data”包含一个新元素,而动画淡出未完成(需要 3000 毫秒)。那就是解释你的问题。

要解决此问题,您必须为“addItem”设置与“fadeout”相同的间隔,例如它是 3000。代码变为:

jQuery(function ($) {
    var ViewModel = function (data) {
        var self = this;
        self.data = ko.observableArray(data);
        self.removeLine = function (elem) {
            if (elem.nodeType === 1) $(elem).fadeOut(3000, function () {
                $(elem).remove();
            });
        }

        self.addLine = function (elem) {
            if (elem.nodeType === 1) 
                $(elem).hide().fadeIn(3000);
        }

        self.removeItem = function() {
            self.data.remove(function(item) { return item.test && item.test == 2; });   
        }

        self.addItem = function() {
            self.data.splice(1, 0, { test: 9 }); 
        }

        self.addremove = function () {
            self.removeItem();
            var id = setInterval(function() {
                self.addItem();
                clearInterval(id);
            },3000); // the same interval as the "fadeout"
        }
    }

    var vm = new ViewModel([{ test: 9 }, { test: 2 }, { test: 1 }, { test: 1 }, { test: 1 }, { test: 1 }, { test: 1 }]);

    ko.applyBindings(vm);
});
于 2016-09-19T20:15:58.177 回答
0

As a workaround, if possible, you want to do all of your changes to the observable array in a single operation. For example, instead of adding and/or removing elements individually, you want to update the entire observable array at once, perhaps using ko.utils.arrayFilter to assign a filtered version of the observableArray back to itself.

self.data( ko.utils.arrayFilter(self.data(), function(x) {
    return shouldKeepElement(x);
}) );

If this is not possible (as is probably the case for you), you'll need to delay the adding of the item into the array until the remove animation is complete. This will probably involve an elaborate system of "levers and pulleys", so the resulting code is going to be pretty undesirable. The user experience will possibly also suffer, since "fast" user actions are going to need to be queued or disallowed.

Obviously an ideal solution is that this gets addressed in the next release of knockout. Until then, you can either "downgrade" to 2.1, or make a small patch to the existing knockout codebase. I can't vouch for this patch, and it may have undesirable consequences, but it should be a good stop-gap for this problem.

于 2014-10-30T03:43:00.580 回答
0

问题在于 addItem 的时间——在开始添加新项目的过程之前,您需要等待动画结束。

工作小提琴:http: //jsfiddle.net/bPP5Q/26/

jQuery(function ($) {
// this runs after the window loads
var ViewModel = function (data) {
    var self = this;
    self.data = ko.observableArray(data);
    self.removeLine = function (elem) {
        if (elem.nodeType === 1) $(elem).fadeOut(3000, function () {
            $(elem).remove();
            self.addItem();
        });
    }

    self.addLine = function (elem) {
        if (elem.nodeType === 1) 
            $(elem).hide().fadeIn(3000);
    }

    self.removeItem = function() {
        self.data.remove(function(item) { return item.test && item.test == 2; });   
    }

    self.addItem = function() {
        self.data.splice(1, 0, { test: 9 }); 
    }

    self.addremove = function () {
        self.removeItem();
    }
}


var vm = new ViewModel([{
    test: 9
}, {
    test: 2
}, {
    test: 1
}, {
    test: 1
}, {
    test: 1
}, {
    test: 1
}, {
    test: 1
}]);

ko.applyBindings(vm);

});
于 2016-04-14T18:06:26.410 回答
0

此处描述的问题已在 3.4.0 中修复。见https://github.com/knockout/knockout/issues/790

于 2016-10-13T13:25:40.297 回答
0

混合 'splice' 和敲除的 'array.remove' 可能会导致意外行为,您最好始终如一地处理它,例如,只使用如下所示的 'splice':

                self.addItem = function () {
                    var index = $.map(self.data(), function (item, index) {
                        if (item.test && item.test == 2) {
                            return index;
                        }
                    })[0];
                    self.data.splice(index + 1, 0, { test: 9 });
                    self.data.splice(index, 1);
                }

                self.addremove = function () {
                    //self.removeItem();
                    var id = setInterval(function () {
                        self.addItem();
                        clearInterval(id);
                    }, 1000);
                }
于 2016-09-23T07:45:14.353 回答
-1

更新了您的示例,我认为只有 aumeti 时间将项目添加到 1 秒到 3

self.removeItem();
var id = setInterval(function() {
  self.addItem();
  clearInterval(id);
},3000);

http://jsfiddle.net/bPP5Q/15/

于 2013-12-13T16:09:01.223 回答
-1

您可以使用 beforeAdd 绑定在显示添加的元素时删除项目

** 编辑 **

这是小提琴:http: //jsfiddle.net/janarde/U6Um5/5/

<button id="button" data-bind="click: addremove">Click</button>
<table id="grid">
    <tbody data-bind='template: { foreach: data, afterAdd: addLine, beforeAdd: removeLine }'>
        <tr>
            <td data-bind="text: test"></td>
            <td>

            </td>
        </tr>
    </tbody>
</table>
于 2013-12-05T13:28:07.247 回答