AngularJS:用动画替换ng-repeat中的两个项目

时间:2014-06-01 22:08:40

标签: javascript angularjs ng-animate

我有一个项目列表,每个项目都有一个唯一的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 =

http://plnkr.co/edit/5AVhz81x3ZjzQFJKM0Iw?p=preview

2 个答案:

答案 0 :(得分:4)

在玩完之后,我确实找到了一个非常hacky的解决方案确实改变了数组中的项目顺序

<强> =思想=

  1. 正如Zack和其他许多建议的那样,我们会在每个项目中记录显示位置( item.x ),用它来确定dom位置

    <div class="item" ng-repeat="item in arr track by item.id" 
    ng-style="getAbsPos(item.x)" >{{item.id}}</div>
    
  2. 交换时,首先重新排序数组,因为dom位置由item.x确定,而不是$ index,不会触发动画;

     var a= arr[0];
     var c = arr[2];
     arr[0] = c;
     arr[2] = a; 
    
  3. 以异步方式交换两个项目的item.x值(使用$timeout),因此angular将步骤2和3视为两个独立的dom更改,仅步骤3将触发动画。

     $timeout(function(){
         var tempX = a.x;
     a.x = c.x;
     c.x = tempX;           
     },10)   
    
  4. 执行批量交换操作时,这可能会产生一些问题。但是对于用户触发的简单两项交换(我的用例),似乎工作正常。

    请告诉我是否有更好的解决方案,谢谢。

    = Plunker demo =

    http://plnkr.co/edit/Vjj9qCcoqMCyuOhNYKKY?p=preview

答案 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"); 
            });
        }
    }
});