【问题标题】:AngularJS: swap two items in ng-repeater with animationAngularJS:用动画交换 ng-repeater 中的两个项目
【发布时间】:2014-07-22 00:14:16
【问题描述】:

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

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

【问题讨论】:

  • @Blackhole 嗨,谢谢。我的情况实际上需要重新排序数组,提供的解决方案似乎通过向每个项目添加额外的位置信息来伪造重新排序。
  • 哦,其实其他问题也没有很好的解决办法;)。实际上,它看起来像一个错误(see this comment,它完美地描述了您的用例)。
  • 在玩 Plunker 时,我得到了这个:plnkr.co/edit/npxFVh9FII0akVj6lIwp?p=preview - 如果你有 DOM 元素检查器,并在动画完成前多次单击按钮,你会看到额外的 DOM 节点添加...奇怪的行为。这无济于事,但会显示相关的意外行为。
  • @J.Bruni 这似乎是 ngAnimate 模块的特性,它会根据 css 转换值自动为 dom 更改添加延迟。

标签: javascript angularjs ng-animate


【解决方案1】:

在玩了之后,我确实找到了一个非常 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. swap时,先对数组重新排序,因为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)   
    

这可能会在执行批量交换操作时产生一些问题。但是对于用户触发的简单的两个项目交换(我的用例),它似乎工作正常。

如果有更好的解决方案请告诉我,谢谢。

=Plunker 演示=

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

【讨论】:

    【解决方案2】:

    一个想法是使用您自己的左标记,而不是 $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"); 
                });
            }
        }
    });
    

    【讨论】:

    • 您好,感谢您的回答。我确实知道这种方法,但是我的应用程序需要通过索引实时大量访问元素(具有大量项目)。 getElementByLeftValue() 在这种情况下会非常昂贵。也许一些额外的数据结构会有所帮助?
    • 一个想法是保持第二个数组按左排序,并让它映射到主数组中的索引。同样,这是很多数据,但是如果您要处理大量数据,那么 angularjs 可能无论如何都不是要走的路。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-25
    • 1970-01-01
    • 2018-05-12
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    相关资源
    最近更新 更多