30

我正在使用这样ng-repeatorderBy过滤器渲染对象列表:

<li class="list-item" ng-repeat="item in items | orderBy:predicate:reverse">

我尝试对列表排序进行 ng-animation 更改已被证明令人沮丧,不值得分享。我在这里看到了 Yearofmoo 示例应用程序。

不幸的是,这个演示并不是我想要实现的。我需要在orderBy定义更改后以新顺序放置给定列表项的 X 位置时设置动画。我试图通过 css 过渡和绝对定位来实现这一点,但ng-repeat似乎重新创建了orderBy使动画成为真正挑战的列表项。

  1. ng-repeat | orderBy(有或没有 ng-animate)这可能吗?
  2. 你能建议一种方法或提供一个例子吗?
4

2 回答 2

42

所以,即使@Alex Osborn 在评论中展示了一种方法来做你想做的事,这也是我的尝试:

angular.module('StackApp', []).controller('MainCtrl', function($scope) {
  'use strict';

  $scope.reverse = 'false';

  $scope.myList = [{
    id: 0,
    text: 'HTML5 Boilerplate'
  }, {
    id: 1,
    text: 'AngularJS'
  }, {
    id: 2,
    text: 'Karma'
  }, {
    id: 3,
    text: 'Hello'
  }, {
    id: 4,
    text: 'World'
  }, {
    id: 5,
    text: 'How'
  }, {
    id: 6,
    text: 'Are'
  }, {
    id: 7,
    text: 'You'
  }, {
    id: 8,
    text: '?'
  }, {
    id: 9,
    text: 'I'
  }, {
    id: 10,
    text: 'write'
  }, {
    id: 11,
    text: 'more'
  }, {
    id: 12,
    text: 'to'
  }, {
    id: 13,
    text: 'make'
  }, {
    id: 14,
    text: 'the'
  }, {
    id: 15,
    text: 'list'
  }, {
    id: 16,
    text: 'longer'
  }];

  $scope.$watch('reverse', function() {
    $scope.setOrder();
  });

  $scope.setOrder = function() {

    if ($scope.reverse === 'random') {

      var t = [];

      for (var i = 0; i < $scope.myList.length; i++) {
        var r = Math.floor(Math.random() * $scope.myList.length);
        while (inArray(t, r)) {
          r = Math.floor(Math.random() * $scope.myList.length);
        }
        t.push(r);
        $scope.myList[i].order = r;
      }

    } else {

      for (var i = 0; i < $scope.myList.length; i++) {
        if ($scope.reverse === 'false') {
          $scope.myList[i].order = i;
        } else {
          $scope.myList[i].order = ($scope.myList.length - 1 - i);
        }
      }
    }
  };

  function inArray(a, value) {
    for (var i = 0; i < a.length; i++) {
      if (a[i] === value) {
        return true;
      }
    }
    return false;
  }

});
#list {
  /* Needed, otherwise items would be at top of the page (see below) */
  position: absolute;
  /* full width, or it would look strange */
  width: 100%;
}
#list li {
  position: absolute;
  /* Top: 0; this will be changed for every single list item by AngularJS */
  top: 0;
  /* Item height; hold this in sync with template file */
  height: 40px;
  /*  Simple transition */
  -webkit-transition: top 0.5s ease-in-out;
  -moz-transition: top 0.5s ease-in-out;
  transition: top 0.5s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="StackApp">
  <div ng-controller="MainCtrl">
    <h1>Animate Order</h1>
    <form action="">
      <label for="reverse">reverse = true</label>
      <br>
      <input type="radio" value="true" name="reverse" ng-model="reverse">
      <br>
      <br>
      <label for="reverse">reverse = false</label>
      <br>
      <input type="radio" value="false" name="reverse" ng-model="reverse">
      <br>
      <br>
      <label for="reverse">reverse = random (click button below to shuffle again)</label>
      <br>
      <input type="radio" value="random" name="reverse" ng-model="reverse">
    </form>
    <br>
    <br>
    <input type="button" ng-click="reverse = 'random';setOrder()" value="setOrder()">
    <br>
    <br>
    <ul id="list" ng-style="{height: ((myList.length * 40) + 'px')}">
      <li ng-repeat="item in myList" ng-style="{top: ((item.order * 40) + 'px')}">{{$index}} - {{item.order}}. {{item.text}}</li>
    </ul>
  </div>
</div>

因此,AngularJS 不会对项目进行排序,但会更改 CSS 属性top( ng-style="{top: ...}")。AngularJS 不会重新创建列表,我们会得到一个不错的动画。:)

于 2013-05-21T12:24:23.600 回答
11

我已经扩展了 AndreM96 的答案以允许将列表显示为网格。

angular.module('StackApp', []).config(function($routeProvider) {

  'use strict';

  $routeProvider
    .when('/', {
      template: '<h1>Animate Order</h1>' +
        '<form action="">' +
        '<input type="radio" value="true" name="order" ng-model="order">' +
        '<label for="order">reverse</label><br><br>' +

        '<input type="radio" value="false" name="order" ng-model="order">' +
        '<label for="order">normal</label><br><br>' +

        '<input type="radio" value="random" name="order" ng-model="order">' +
        '<label for="order">random (click button below to shuffle again)</label><br>' +

        '</form>' +
        '<input type="button" ng-click="order = \'random\';setOrder()" value="randomize">' +
        '<br><br>' +
        '<ul id="list" ng-style="{height: ((myList.length * 90) + \'px\')}">' +
        '<li ng-repeat="item in myList" ng-style="{top: ((item.row * 90) + \'px\'), left: ((item.column * 90) + \'px\')}">{{$index}} - {{item.order}}. {{item.text}}</li>' +
        '</ul>',
      controller: 'MainCtrl'
    })
    .otherwise({
      redirectTo: '/'
    });

});

angular.module('StackApp').controller('MainCtrl', function($scope) {
  'use strict';

  $scope.order = 'false';

  $scope.myList = [{
      id: 0,
      text: 'HTML5 Boilerplate'
    },
    {
      id: 1,
      text: 'AngularJS'
    },
    {
      id: 2,
      text: 'Karma'
    },
    {
      id: 3,
      text: 'Hello'
    },
    {
      id: 4,
      text: 'World'
    },
    {
      id: 5,
      text: 'How'
    },
    {
      id: 6,
      text: 'Are'
    },
    {
      id: 7,
      text: 'You'
    },
    {
      id: 8,
      text: '?'
    },
    {
      id: 9,
      text: 'I'
    },
    {
      id: 10,
      text: 'write'
    },
    {
      id: 11,
      text: 'more'
    },
    {
      id: 12,
      text: 'to'
    },
    {
      id: 13,
      text: 'make'
    },
    {
      id: 14,
      text: 'the'
    },
    {
      id: 15,
      text: 'list'
    },
    {
      id: 16,
      text: 'longer'
    }
  ];

  $scope.$watch('order', function() {
    $scope.setOrder();
  });

  $scope.setOrder = function() {

    var i;

    if ($scope.order === 'random') {
      var t = [];
      for (i = 0; i < $scope.myList.length; i++) {
        var r = Math.floor(Math.random() * $scope.myList.length);
        while (inArray(t, r)) {
          r = Math.floor(Math.random() * $scope.myList.length);
        }
        t.push(r);
        $scope.myList[i].order = r;
      }
    } else if ($scope.order === 'false') {
      for (i = 0; i < $scope.myList.length; i++) {
        $scope.myList[i].order = i;
      }
    } else {
      for (i = 0; i < $scope.myList.length; i++) {
        $scope.myList[i].order = ($scope.myList.length - 1 - i);
      }
    }

    calcGridPosition();
  };

  function inArray(a, value) {
    for (var i = 0; i < a.length; i++) {
      if (a[i] === value) {
        return true;
      }
    }
    return false;
  }

  function calcGridPosition() {
    for (var i = 0; i < $scope.myList.length; i++) {
      var item = $scope.myList[i];

      // columns, left-to-right, top-to-bottom
      var columns = 5;
      item.column = item.order % columns;
      item.row = Math.floor(item.order / columns);

      // rows, top-to-bottom, left-to-right
      // var rows = 3;
      // item.column = Math.floor(item.order/rows);
      // item.row = item.order%rows;
    }
  }

});
#list {
  position: absolute;
  width: 100%;
  list-style-type: none;
  padding-left: 0;
}

#list li {
  position: absolute;
  height: 70px;
  width: 70px;
  background: #ddd;
  -webkit-transition: all 2.5s ease-in-out;
  -moz-transition: all 2.5s ease-in-out;
  transition: all 2.5s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js"></script>
<main ng-app="StackApp">
  <div class="container" ng-view></div>
</main>

JSBin 演示

在此处输入图像描述

于 2014-02-03T21:06:59.667 回答