当一个被删除时,如何为剩余的 ng-repeat 项目的移动设置动画?

Posted

技术标签:

【中文标题】当一个被删除时,如何为剩余的 ng-repeat 项目的移动设置动画?【英文标题】:How can I animate the movement of remaining ng-repeat items when one is removed? 【发布时间】:2014-05-24 18:12:21 【问题描述】:

我有一个使用 ng-repeat 的动态项目列表。当某事发生时,一个项目可能会消失。我已经使用 ng-animate 顺利地处理了这些项目的删除动画,但是在它们消失后,剩余的项目会简单地捕捉到它们的新位置。我怎样才能顺利地为这个动作制作动画?

我尝试将“全部”转换应用于重复的类并使用 ng-move 没有成功。

【问题讨论】:

你看到了吗:nganimate.org/angularjs/ng-repeat/move ? @aet,这是针对 Angular 1.1.5 的。我认为该解决方案可能适用于 1.2.x。这是可能的,但需要测试。 很遗憾,ng-move 不适用于这种情况。它仅适用于对 ng-repeat 列表中的项目进行排序或过滤时。在这种情况下,该项目将被完全删除。话虽如此 - 如果我先应用过滤器然后删除该项目,也许我可以“作弊”并获得 ng-move 的好处。会尝试更新。 那行不通。应用过滤器仍然会导致即时移动,而不是平滑过渡。 【参考方案1】:

您可以通过为max-height 属性设置动画来实现此目的。查看此示例:

http://jsfiddle.net/k4sR3/8/

您需要为max-height 选择一个足够高的值(在我的示例中,我使用了 90px)。最初添加项目时,您希望它以 0 高度开始(我也在动画 left 以使项目从左侧滑入,以及 opacity,但如果它们可以删除它们不要嘲笑你在做什么):

.repeated-item.ng-enter 
    -webkit-transition:0.5s linear all;
    -moz-transition:0.5s linear all;
    -o-transition:0.5s linear all;
    transition:0.5s linear all;
    max-height: 0;
    opacity: 0;
    left: -50px;

然后,您在ng-enter-active 规则中设置这些属性的最终值:

.repeated-item.ng-enter.ng-enter-active 
    max-height: 90px;
    opacity: 1;
    left: 0;

项目移除有点棘手,因为您需要使用基于关键帧的动画。同样,您要为max-height 设置动画,但这次您希望从 90px 开始并将其减小到 0。随着动画的运行,项目会缩小,并且所有以下项目都会平滑地向上滑动。

首先,定义您将使用的动画:

@keyframes my_animation 
  from 
    max-height: 90px;
    opacity: 1;
    left: 0;
  
  to 
    max-height: 0;
    opacity: 0;
    left: -50px;
  

(为简洁起见,我在这里省略了供应商特定的定义,@-webkit-keyframes@-moz-keyframes 等 - 查看上面的 jsfiddle 以获取完整示例。)

然后,声明您将使用此动画为ng-leave 如下:

.repeated-item.ng-leave 
  -webkit-animation:0.5s my_animation;
  -moz-animation:0.5s my_animation;
  -o-animation:0.5s my_animation;
  animation:0.5s my_animation;


基础知识

如果有人正在为如何让 AngularJS 动画工作而苦苦挣扎,这里有一个简短的指南。

首先,要启用动画支持,您需要在加载angular.js 之后添加一个附加文件angular-animate.js。例如:

<script type="text/javascript" src="angular-1.2/angular.js"></script>
<script type="text/javascript" src="angular-1.2/angular-animate.js"></script>

接下来,您需要通过将 ngAnimate 添加到模块的依赖项列表(在第二个参数中)来加载它:

var myApp = angular.module('myApp', ['ngAnimate']);

然后,为您的 ng-repeat 项目分配一个类。您将使用此类名称来分配动画。在我的示例中,我使用了repeated-item 作为名称:

<li ng-repeat="item in items" class="repeated-item">

然后,您在 CSS 中使用 repeated-item 类以及特殊类 ng-enterng-leaveng-move 定义动画,Angular 在添加、删除项目时添加到项目中,或四处移动。

AngularJS 动画的官方文档在这里:

http://docs.angularjs.org/guide/animations

【讨论】:

非常感谢!我的问题是我正在使用 transform:scaleY 为离开/进入设置动画,这实际上并没有改变元素的高度,只是它的高度外观。在动画中操纵高度本身就可以了。 这是一个很好的答案!我实际上录制了一个视频 - youtube.com/watch?v=mRItxM1dHFA - 问一个更好的问题,它已经被你解决了!关于“如何设置动画” --> ***.com/questions/21591860/…(非常简单的例子)【参考方案2】:

TLDR: Jank 不好,用变换做动画。查看 this fiddle 获取 css 和演示。


说明

请注意,为heightmax-heighttop 设置动画在性能方面确实很糟糕,因为它们会导致回流并因此卡顿(有关html5rocks|high-performance-animations 的更多信息)。

然而,有一种方法通过使用兄弟选择器仅使用变换来获得这种类型的动画。

当添加元素时,由于新项目而进行了一次重排,下面的所有项目都被转换,因此它们保持在同一位置,然后移除转换以实现平滑滑入。

相反,当元素被移除时,它们会被转换到新位置以实现平滑滑出,当元素最终被移除时,会再次进行一次回流,并且转换会立即被移除,因此它们会保持在原来的位置(这也是为什么只在ng-animate 上设置transition 很重要)。

除了示例之外,您还可以对已删除的项目执行transform: scaleY(0),并且仅对兄弟姐妹执行transform: translateY()

警告

请注意,当多个元素被快速连续删除时(在上一个动画完成之前),这个 sn-p 会出现问题。

这可以通过使动画时间比用户删除另一个项目所花费的时间更快或通过对动画做更多工作来解决(超出此答案的范围)。

终于有代码了

注意:显然 SO 通过多次删除破坏了演示 - 请查看 fiddle 以查看它的工作情况。

angular.module('app', ['ngAnimate'])
  .controller('testCtrl', ['$scope', function($scope) 
    var self = this;
    
    self.items = [];
    
    var i = 65;
    for(; i < 72; i++)
    
    	self.items.push( value: String.fromCharCode(i) );
    
    
    self.addItem = function()
    
    	self.items.push( value: String.fromCharCode(i) );
      i++;
    
    
    self.removeItemAt = function(index)
    
    	self.items.splice(index, 1);
    
  ])
li

  height: 48px;
  width: 300px;
  border: 1px solid lightgrey;
  background-color: white;
  position: relative;
  list-style: none;

li.ng-enter,
li.ng-enter ~ li 
  transform: translateY(-100%);

li.ng-enter.ng-enter-active,
li.ng-enter.ng-enter-active ~ li 
  transform: translateY(0);

li.ng-animate 
  z-index: -1;

li.ng-animate,
li.ng-animate ~ li 
  transition: transform 0.6s;

li.ng-leave,
li.ng-leave ~ li 
  transform: translateY(0);

li.ng-leave.ng-leave-active,
li.ng-leave.ng-leave-active ~ li 
  transform: translateY(-100%);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.23/angular-animate.js"></script>

<div ng-app="app" ng-controller="testCtrl as ctrl">
  <ul>
    <li ng-repeat="item in ctrl.items" ng-bind="item.value">
      
    </li>
  </ul>
  <button ng-click="ctrl.addItem()">
  Add
  </button>
  <button ng-click="ctrl.removeItemAt(5)">
  Remove at 5
  </button>
</div>

【讨论】:

不错。不幸的是,它不能处理不同的项目大小。 jsfiddle.net/Ly9p9kzu/5 对,那可能需要更多的 JS 工作。 检查了小提琴,删除元素后底部按钮仍在向上跳

以上是关于当一个被删除时,如何为剩余的 ng-repeat 项目的移动设置动画?的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript:如何为函数中的任何键键入对象剩余分布

当 React.Dispatch<React.SetStateAction<string>> 不被接受时,如何为 setState 函数定义 TypeScript 类型?

如何为iCarousel iphone中不同位置的图像实现删除功能

JMeter:JDBC 删除不一致

如何为 UITableView 添加自定义 EditingAccessoryView?

当UIVIew隐藏在sameView中时,如何为UIview设置动画