我想看一个使用angular-animate(1.2x)对列表进行排序的功能示例。 (我只是在互联网上遇到破碎的小提琴等):
给出数组[A,B,C]和后来的[C,B,A]的ng-repeat应该:
(使用CSS绝对顶部定位或类似。)
使用交错(过渡延迟)的例子是一个奖励。
答案 0 :(得分:9)
实现你想要的东西可能有点棘手。
一种常见的尝试是使用ng-style
根据列表中的索引计算元素的位置:
<div ng-repeat="c in countries | orderBy:q" ng-style="{ 'top': $index * 20 + 'px' }">
演示: http://plnkr.co/edit/anv4fIrMxVDWuov6K3sw?p=preview
问题是只有一些元素是动画的,而且只是在底部。
为什么?
考虑按名称排序的以下列表(类似于上面演示中的列表):
当您按ID对此列表进行排序时,只会移动一个元素 - 瑞典从下到上。实际发生的是,瑞典元素从DOM中删除并再次插入其新位置。但是,当一个元素插入到DOM中时,通常不会发生相关的CSS转换(我通常会说,因为它最终取决于所讨论的浏览器是如何实现的)。
另外两个元素保留在DOM中,获得新的top
位置,并且它们的过渡是动画的。
因此,使用此策略,转换仅针对实际上未在DOM中移动的元素进行动画处理。
另一种策略是包含ngAnimate模块并使用该CSS类ng-move
。几乎所有动画ng-repeats的例子都使用它。
然而,由于两个原因,这不起作用:
ng-move
类仅适用于移动的元素(因此仅适用于上例中的Sweden元素)
在将元素插入DOM中的新位置后,ng-move
类将应用于该元素。您可以使用“从不透明度0到1的动画”的CSS,但是您不能将“从旧位置动画到新位置”,因为旧位置未知且每个元素都必须移动不同的距离。
我过去使用过的解决方案是使用ng-repeat
来呈现列表但从未实际使用基础数据。这样,所有DOM元素都将保留在DOM中并可以设置动画。要正确渲染元素,请使用ng-style
和自定义属性,例如:
ng-style="{ 'top': country.position * 20 + 'px' }"
要更新position
属性,请执行以下操作:
创建基础数据的副本
您可以使用angular.copy
复制整个阵列,但对于大型阵列,这对性能不利。它也是不必要的,因为复制数组中的每个对象只需要一个唯一的属性和要排序的属性:
var tempArray = countries.map(function(country) {
var obj = {
id: country.id
};
obj[property] = country[property];
return obj;
});
在上面的示例中,id
是唯一属性,property
是一个变量,包含要排序的属性的名称,例如name
。
对副本进行排序
要使用比较函数对数组进行排序,请使用Array.prototype.sort()
:
tempArray.sort(function(a, b) {
if (a[property] > b[property])
return 1;
if (a[property] < b[property])
return -1;
return 0;
});
在排序副本中将位置设置为元素的索引
countries.forEach(function(country) {
country.position = getNewPosition(country.id);
});
function getNewPosition(countryId) {
for (var i = 0, length = tempArray.length; i < length; i++) {
if (tempArray[i].id === countryId) return i;
}
}
还有改进的余地,但这是它的基础。
演示: http://plnkr.co/edit/2Ramkg3sMW9pds9ZF1oc?p=preview
我实现了一个使用惊人的版本,但它看起来有点奇怪,因为元素会暂时重叠。
答案 1 :(得分:0)
看看这个,非常简单: CSS:
.animate-enter,
.animate-leave
{
-webkit-transition: 400ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
-moz-transition: 400ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
-ms-transition: 400ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
-o-transition: 400ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
transition: 400ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
position: relative;
display: block;
}
.animate-enter.animate-enter-active,
.animate-leave {
opacity: 1;
top: 0;
height: 30px;
}
.animate-leave.animate-leave-active,
.animate-enter {
opacity: 0;
top: -50px;
height: 0px;
}
HTML:
<!doctype html>
<html ng-app>
<head>
<meta charset="utf-8">
<title>Top Animation</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css">
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">
<script src="http://code.angularjs.org/1.1.5/angular.js"></script>
</head>
<body ng-init="names=['Igor Minar', 'Brad Green', 'Dave Geddes', 'Naomi Black', 'Greg Weber', 'Dean Sofer', 'Wes Alvaro', 'John Scott', 'Daniel Nadasi'];">
<div class="well" style="margin-top: 30px; width: 200px; overflow: hidden;">
<ul class="nav nav-pills nav-stacked">
<li ng-animate="'animate'" ng-repeat="name in names">
<a href="#"> {{name}} </a>
</li>
</ul>
</form>
</div>
</body>
</html>