如何在 Vue 中删除列表项时为列表项设置动画

Posted

技术标签:

【中文标题】如何在 Vue 中删除列表项时为列表项设置动画【英文标题】:How to animate list items in Vue when one is removed 【发布时间】:2018-10-22 23:28:10 【问题描述】:

我有一个垂直的项目列表,每个项目都可以删除。我将我的项目放在一个过渡组中,并为它们创建了简单的不透明度和变换过渡。已移除元素上的转换按预期工作,但是如果我移除一个未放置在底部的元素,则下方的元素只会跳起来并在没有任何转换的情况下取代它。我找不到针对这种行为的方法。 我想要的只是下面的元素平滑地向上滑动。

有没有什么办法可以通过使用 css transitipms 和 Vue 的动画钩子来实现这个效果?

这是一个演示:https://jsfiddle.net/gcp18nq0/

模板:

<div id="app">
 <div class="form">
  <label for="name">Name</label>
  <input type="text" id="name" v-model="name">
  <button @click="addPlayer">Add player</button>
 </div>
 <div class="players">
  <transition-group name="player">
   <div class="panel" v-for="player in players" :key="player.id">
    <h2>
       player.name
      <span class="remove" @click="removePlayer(player.id)">Remove</span>
    </h2>
   </div>
  </transition-group>
 </div>
</div>

脚本:

  data() 
    return 
     name: "",
     players: [
       id: 1, name: 'Player1',
       id: 2, name: 'Player2',
       id: 3, name: 'Player3',
     ]
    
  ,
  methods: 
            addPlayer: function () 
                  //,,,,
                ,
            removePlayer: function (playerId) 
                   //...
            
         
  );

CSS

.form 
  margin:0 auto;
  width:400px;

.panel 
  width: 400px;
  margin: 10px auto;
  overflow: hidden;
  border: 1px solid;
  text-align: center;


.remove 
  float: right;
  cursor: pointer;
  text-decoration: underline;
  font-size: 12px;
  vertical-align: bottom


.player-enter,
.player-leave-to
/* .fade-leave-active below version 2.1.8 */

  
  opacity: 0;


.player-enter 
  transform: translateY(30%);


.player-leave-to 
  transform: translateX(30%);


.player-enter-active,
.player-leave-active 
  transition: all 1.5s;


.player-move 
  transition: all 1.5s;

我发现的唯一工作方式是在“player-leave-active”状态下添加 position:absolute,但由于元素折叠,它会改变其垂直位置,这不是预期的效果。我也尝试改变高度,但是在高度设置为 0 后,下面的元素仍然会向上跳跃一点。 我确信这可以通过 jQuery 轻松实现,但我相信应该有一种方法可以在没有 js 的情况下做到这一点。

提前感谢您!

附言这是我在这里的第一篇文章,所以我希望它解释得足够清楚。

【问题讨论】:

【参考方案1】:

所以我对你的小提琴做了一些小的调整:https://jsfiddle.net/gcp18nq0/1/,希望这就是你想要的。

根据Vue documentation,最重要的变化是在.panel 类上设置display: inline-block

一个重要的注意事项是这些 FLIP 过渡不适用于 元素设置为 display: inline。作为替代方案,您可以使用 display: inline-block 或将元素放置在 flex 上下文中。

new Vue(
  el: "#app",
  data() 
    return 
      name: "",
      players: [
          id: 1,
          name: 'Batman'
        ,
        
          id: 2,
          name: 'Robin'
        ,
        
          id: 3,
          name: 'Superman'
        ,
        
          id: 4,
          name: 'Spiderman'
        ,
      ]
    
  ,
  methods: 
    addPlayer: function() 
      const newPlayer = 
        id: this.players.length + 1,
        name: this.name,
      ;
      this.players.push(newPlayer);
    ,
    deletePlayer: function(playerId) 
      let playerToRemove = this.players.find((player) => 
        return player.id === playerId;
      );

      let playerIndex = this.players.indexOf(playerToRemove);
      this.players.splice(playerIndex, 1);
    
  
);
.form 
  margin: 0 auto;
  width: 400px;


.panel 
  width: 400px;
  margin: 6px auto;
  overflow: hidden;
  border: 1px solid;
  text-align: center;
  transition: all 1s;
  display: inline-block;


.players 
  position: relative;
  text-align: center;


.remove 
  float: right;
  cursor: pointer;
  text-decoration: underline;
  font-size: 12px;
  vertical-align: bottom


.player-enter,
.player-leave-to 
  opacity: 0;


.player-enter 
  transform: translateY(30%);


.player-leave-to 
  transform: translateX(300%);


.player-leave-active 
  position: absolute;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
  <div class="form">
    <label for="name">Name</label>
    <input type="text" id="name" v-model="name">
    <button @click="addPlayer">Add player</button>
  </div>
  <div class="players">
    <transition-group name="player" tag="div">
      <div class="panel" v-for="player in players" :key="player.id">
        <h2>
           player.name
          <span class="remove" @click="deletePlayer(player.id)">Remove</span>
        </h2>
      </div>
    </transition-group>
  </div>
</div>

【讨论】:

这里的另一个增强功能是在整个列表高度发生变化时也让父容器平滑过渡。现在,当行出现/消失时,父容器会跳转。

以上是关于如何在 Vue 中删除列表项时为列表项设置动画的主要内容,如果未能解决你的问题,请参考以下文章

如何在颤动中使用动画列表对最初渲染的项目进行动画处理

React:如何在内容大小未知时为展开和折叠 Div 设置动画

在链接悬停时为 SVG 设置动画

检查时如何在列表视图中删除文本项?

创建新菜单项时为 joomla 组件创建新选项

如何在选择列表项时将文本框附加到来自共享点列表的复选框列表项