我遇到了敲门js的问题,并将一个可观察的数组显示为列表;在beforeRemove动画运行时添加项目时,删除的元素将移动到列表的底部,而不是保持其位置,直到动画完成并删除元素。
这是一个更好地解释问题的方法: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>
答案 0 :(得分:1)
您的函数“addItem”在1秒后执行(setInterval 1000 ms),因此“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);
});
答案 1 :(得分:0)
作为一种解决方法,如果可能,您希望在单个操作中对可观察数组进行所有更改。例如,您不想单独添加和/或删除元素,而是希望立即更新整个observable数组,可能使用ko.utils.arrayFilter将observableArray的过滤版本分配回自身。
self.data( ko.utils.arrayFilter(self.data(), function(x) {
return shouldKeepElement(x);
}) );
如果无法做到这一点(可能就是这种情况),您需要延迟将项目添加到数组中,直到删除动画完成为止。这可能涉及一个精心设计的“杠杆和滑轮”系统,因此产生的代码将是非常不受欢迎的。用户体验也可能受到影响,因为“快速”用户操作需要排队或禁止。
显然,理想的解决方案是在下一个淘汰版本中解决这个问题。在此之前,您可以“降级”到2.1,或者a small patch到现有的淘汰代码库。我不能保证这个补丁,它可能会产生不良后果,但它应该是这个问题的一个良好的止损。
答案 2 :(得分: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);
});
答案 3 :(得分:0)
混合&#39;拼接&#39;和淘汰的阵列。删除&#39;可能会导致意外行为,您可以更好地一致地处理它,例如,只使用&#39; splice&#39;如下所示:
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);
}
答案 4 :(得分:0)
此处描述的问题已在3.4.0中修复。见https://github.com/knockout/knockout/issues/790
答案 5 :(得分:-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>
答案 6 :(得分:-1)
更新了我认为仅按照预期将项目添加到1秒到3的预期示例
self.removeItem();
var id = setInterval(function() {
self.addItem();
clearInterval(id);
},3000);