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ミリ秒)後に実行されるため、アニメーションのフェードアウトが完了していない間(3000ミリ秒が必要)、「self.data」に新しい要素が含まれます。それはあなたの問題を説明しています。

この問題を解決するには、「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

回避策として、可能であれば、監視可能な配列へのすべての変更を 1 回の操作で行うことをお勧めします。たとえば、要素を個別に追加または削除する代わりに、監視可能な配列全体を一度に更新する必要があります。おそらく ko.utils.arrayFilter を使用して、observableArray のフィルター処理されたバージョンをそれ自体に割り当てます。

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

これが不可能な場合 (おそらくあなたの場合)、削除アニメーションが完了するまで、配列へのアイテムの追加を遅らせる必要があります。これにはおそらく「レバーと滑車」の精巧なシステムが含まれるため、結果として得られるコードはかなり望ましくないものになります。「高速な」ユーザー アクションはキューに入れるか許可しない必要があるため、ユーザー エクスペリエンスも損なわれる可能性があります。

明らかに理想的な解決策は、これがノックアウトの次のリリースで対処されることです。それまでは、2.1 に「ダウングレード」するか、既存のノックアウト コードベースに小さなパッチを作成することができます。このパッチを保証することはできず、望ましくない結果が生じる可能性がありますが、この問題に対する適切な応急処置にはなるはずです。

于 2014-10-30T03:43:00.580 に答える
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

追加された要素を表示するときに、 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 に答える
-1

アイテムを追加するのに1秒から3秒にかかる時間は予想通りだと思うあなたの例を更新しました

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

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

于 2013-12-13T16:09:01.223 に答える