2013-02-12 75 views
33

我有一个knockout js问题,并显示一个可观察数组作为列表;在beforeRemove动画运行时添加项目时,已移除的元素将移动到列表的底部,而不是停留在其位置,直到动画完成并且元素被移除。敲除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> 
+9

这在2.1中正常工作。在2.2中,我们增加了识别项目被移动的功能,而不是删除它并将其添加回来。看起来这是您正在处理的案例造成的问题。我会更深入地研究它。 – 2013-02-12 13:13:43

+1

我降级到2.1,它工作的很好,但有一些其他问题,而不是存在于2.2,所以如果这可以解决任何其他方式,将是伟大的! – Cyriuz 2013-02-19 09:59:30

+1

这方面的更新?我与Knockout 3.0有同样的问题,你可以在这里看到我的例子:http://jsfiddle.net/davertron/3ucVg/1/ – davertron 2014-03-16 17:44:25

回答

-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> 
+0

我不认为这回答了这个问题。 Cyriuz想知道如何删除的项目可以继续显示,因为它是退出动画播放。 – aaaidan 2014-10-30 00:24:47

-1

更新你的榜样,我认为是因为预期仅aumeti时间的项目添加到1秒3

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

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

+0

此答案不能解决问题。您更改过的代码的目的是为了演示出现问题的场景。你的改变只是改变了情况,所以问题没有显现。 – aaaidan 2014-10-30 03:52:18

0

作为一种变通方法,如果可能的话,你想干什么在单个操作中对可观察数组的所有更改。例如,不是单独添加和/或删除元素,而是希望一次更新整个可观察数组,可能使用ko.utils.arrayFilter将已过滤版本的observableArray指派回自己。

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

如果这是不可能的(这可能正是你的情况下),你就需要推迟项目的添加到阵列中,直至删除动画完成。这可能涉及到一个精心设计的“杠杆和滑轮”系统,所以最终的代码将会非常不可取。用户体验可能也会受到影响,因为“快速”用户操作将需要排队或不允许。

显然,一个理想的解决方案是,这在下一个版本的淘汰赛中得到解决。在此之前,您可以“降级”到2.1,或者将a small patch升级到现有的基础代码库。我不能担保这个补丁,它可能会有不良后果,但它应该是这个问题的一个很好的障碍。

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); 

}); 
1

你的函数“的addItem”之后1秒(setInterval的1000毫秒)执行,因此“self.data”包含了新的元素,而动画淡出是不完整的(这是需要3000毫秒)。这是解释你的问题。

要解决此问题,您必须使“addItem”与“淡出”的间隔相同,例如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); 
}); 
0

混合“拼接”和基因敲除的“array.remove”可能会导致意外的行为,你最好处理它始终如一,例如,只使用“剪”象下面这样:

   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); 
       } 
0

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

+0

由于这个问题已经吸引了很多观点和相当多的投票,或许这个答案实际上会更好,因为编辑问题让未来的人知道它现在不适用。否则,它应该是对原始问题的评论。当你有足够的声誉,你可以评论问题。 – Mike 2016-10-13 14:44:13