我有一个项目列表,每个项目都有一个唯一的ID
$scope.arr = [{val:0,id:'a'},{val:1,id:'b'},{val:2,id:'c'}];
每个项目根据其$ index
绝对定位<div class="item" ng-repeat="item in arr track by item.id"
ng-style="getAbsPos($index)" >{{item.id}}</div>
我想要的只是在数组中交换arr[0]
和arr[2]
,并且显示此动作的移动动画。结果证明非常困难。
我认为这个css会起作用,因为列表是由id
跟踪的.item{
transition:all 3000ms;
}
但不知何故角度决定只移动其中一个项目dom 并重新创建另一个项目(为什么?!)。因此,只有一个项目是动画的。
=问题=
是否有解决此问题的解决方案,因此两个项目在交换时都会动画?感谢。
(必须实际交换项目在数组中的位置,以便可以通过正确的索引轻松访问它)
=请参阅Plunker demo =
答案 0 :(得分:4)
在玩完之后,我确实找到了一个非常hacky的解决方案确实改变了数组中的项目顺序:
<强> =思想= 强>
正如Zack和其他许多建议的那样,我们会在每个项目中记录显示位置( item.x ),用它来确定dom位置
<div class="item" ng-repeat="item in arr track by item.id"
ng-style="getAbsPos(item.x)" >{{item.id}}</div>
交换时,首先重新排序数组,因为dom位置由item.x确定,而不是$ index,不会触发动画;
var a= arr[0];
var c = arr[2];
arr[0] = c;
arr[2] = a;
以异步方式交换两个项目的item.x值(使用$timeout
),因此angular将步骤2和3视为两个独立的dom更改,仅步骤3将触发动画。
$timeout(function(){
var tempX = a.x;
a.x = c.x;
c.x = tempX;
},10)
执行批量交换操作时,这可能会产生一些问题。但是对于用户触发的简单两项交换(我的用例),似乎工作正常。
请告诉我是否有更好的解决方案,谢谢。
= Plunker demo =
答案 1 :(得分:0)
一个想法是使用你自己的左标记,而不是$ index。下面是一个使用指令监视对象.left属性的示例。在这种情况下,如果需要将实际数组发布到服务器或其他某个位置,可以使用.left重新排序实际数组。这是随附的JSFIDDLE。
HTML
<div class="item" ng-repeat="item in list" move-to="item.left">{{item.id}} / {{$index}}</div>
module.controller('myCtrl', function($scope) {
$scope.list = [
{val:0, id:'a', left: 0},
{val:1, id:'b', left: 100},
{val:2, id:'c', left: 200}
];
$scope.swap = function() {
var a_left = $scope.list[0].left
$scope.list[0].left = $scope.list[2].left;
$scope.list[2].left = a_left;
}
})
.directive('moveTo', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
scope.$watch(attrs.moveTo, function(newVal) {
elem.css('left', newVal + "px");
});
}
}
});