我正在使用foreach绑定和beforeRemove回调,以便为我的列表项的移除设置动画。当我删除之前删除的项目上方的项目时工作正常,但当我尝试删除之前删除的项目下方的项目时,转换无法正常工作。
这是一个说明我的问题的jsfiddle:http://jsfiddle.net/tylerweeres/2szjxzs0/2/
HTML
<h3>Animations</h3>
<div data-bind="foreach: { data: people, beforeRemove: animateOut }">
<div style="padding: 5px;" class="person">
<span data-bind="text: name" style="display: inline-block; width: 200px;"></span>
<button style="padding: 5px 15px;" data-bind="click: $parent.removePerson">Remove</button>
</div>
</div>
CSS
.person {
font-family: georgia;
padding: 5px;
transition: all 600ms ease-in-out;
transform-origin: 75px;
}
.person.remove {
transform: translateX(2000px) rotateZ(540deg);
}
JS
function vm () {
"use strict";
var me = this;
me.people = ko.observableArray([
{ "name": "Irma Olsen" },
{ "name": "Winifred Cabrera" },
// ...
{ "name": "Lucius Howard" },
{ "name": "Hedda Santana" }
]);
me.removePerson = function (person) {
me.people.remove(person);
};
me.animateOut = function animateOut(node, i, person) {
// Make sure it's not a text node
if (node.nodeType == Node.ELEMENT_NODE) {
node.classList.add("remove");
}
}
}
ko.applyBindings(new vm());
答案 0 :(得分:2)
这是一个奇怪的,但我认为它与疯狂的浏览器渲染逻辑的东西有关。你需要强制重绘不会发生。有一点我们有:
<div class="person remove">
<div class="person">
然后我们去
<div class=person>
<div class=person>
同一个div不再有remove
类了 - 当我们添加remove
类时,Knockout会删除数据,但是浏览器不知道更新这个div,所以它不会执行转换,这意味着transitionEnd
不会触发,也不会删除div。
那么我们如何强制重绘? Obviously by calling node.offsetHeight
(一个有效的表达式)。
http://jsfiddle.net/ExplosionPIlls/2szjxzs0/6/
我相信有人可以更有说服力地解释这是如何运作的,以及为什么需要这样做,但至少应该解决你当前的问题。
答案 1 :(得分:2)
来自beforeRemove
事件的documentation:
beforeRemove
- 在删除数组项时调用,但是 在删除相应的DOM节点之前。如果你指定一个 beforeRemove回调,然后你有责任删除 DOM节点。
在beforeRemove
中,如果DOM节点不是文本节点,则只删除所有节点。
因此,您需要使用else
添加node.parentElement.removeChild(node);
案例:
me.animateOut = function animateOut(node, i, person) {
// Make sure it's not a text node
if (node.nodeType == Node.ELEMENT_NODE) {
node.addEventListener("transitionend", function () {
this.parentElement.removeChild(this);
});
node.classList.add("remove");
}
else{
node.parentElement.removeChild(node);
}
}
演示JSFiddle。
答案 2 :(得分:1)
您的转换在remove
发生后结束,因此可能会使渲染变得混乱。
您可以通过通知people
集合转换已结束来解决此问题。
me.animateOut = function animateOut(node, i, person) {
// Make sure it's not a text node
if (node.nodeType == Node.ELEMENT_NODE) {
node.addEventListener("transitionend", function () {
this.parentElement.removeChild(this);
me.people.notifySubscribers(); // Add this line here
});
node.classList.add("remove");
}
}
请注意,如果您有手动订阅,他们将收到通知回调的undefined
参数通知,因此您应该为此做好准备。