如何用Vue.js动画化列表排序

How to animate the sorting of a list with Vue.js

本文关键字:列表 排序 动画 js 何用 Vue      更新时间:2023-09-26

我试图用Vue.js动画列表排序,但并非所有项目都是动画的。你知道为什么吗?如何让它发挥作用?

new Vue({
  el: '#app',
  data: {
    reverse: 1,
    items: [
      { name: 'Foo' },
      { name: 'Bar' },
      { name: 'Baz' },
      { name: 'Qux' }
    ]
  }
})
.moving-item {
  transition: all 1s ease;
  -webkit-transition: all 1s ease;
}
ul {
  list-style-type: none;
  padding: 0;
  position: relative;
}
li {
  position: absolute;
  border: 1px solid #42b983;
  height: 20px;
  width: 150px;
  padding: 5px;
  margin-bottom: 5px;
  color: #42b983;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.0-alpha.2/vue.min.js"></script>
<div id="app">
  <button on-click="reverse = Math.abs(reverse-1)">
    <span v-if="reverse == 0">△</span>
    <span v-if="reverse == 1">▽</span> Order
  </button>
  <ul>
    <li class="moving-item" v-for="item in items | orderBy 'name' reverse" bind-style="{ top: ($index * 35) + 'px'}">{{ item.name }}</li>
  </ul>  
</div>

我认为问题是在排序期间只有一个元素留在DOM中。其他三个正在被移除并重新插入以满足新的顺序-但因此它们不会触发动画。

通常,动画是使用Vue转换系统(http://vuejs.org/guide/transitions.html)完成的。但是,使用该技术会出现相同的基本问题,即删除和重新插入不跟踪位置状态。通常,项目的动画与它们以前和新的位置无关(比如在旧位置淡出,在新位置淡入)。

如果你真的需要从旧位置动画到新位置,我认为你需要编写自己的Javascript转换,在每个项目被删除之前记住它的先前位置,并在插入时将其动画到新位置。

这里有一个例子,应该是一个很好的起点:http://vuejs.org/guide/transitions.html#JavaScript_Only_Transitions

另一个选择是不按过滤器排序,而是在javascript中进行排序(这样v-for只呈现一次)。然后在你的条目上针对一个新的索引参数设置bind-style,如下所示:

new Vue({
  el: '#app',
  data: {
    reverse: 1,
    items: [
      { name: 'Foo', position: 0 },
      { name: 'Bar', position: 1 },
      { name: 'Baz', position: 2 },
      { name: 'Qux', position: 3 }
    ]
  },
  methods: {
    changeOrder: function (event) {
      var self = this;
      self.reverse = self.reverse * -1
      var newItems = self.items.slice().sort(function (a, b) { 
        var result;
        if (a.name < b.name) {
          result = 1
        }
        else if (a.name > b.name) {
          result = -1
        }
        else {
          result = 0
        }
        return result * self.reverse
      })
      newItems.forEach(function (item, index) {
        item.position = index;
      });
    }
  }
})
 
.moving-item {
  transition: all 1s ease;
  -webkit-transition: all 1s ease;
}
ul {
  list-style-type: none;
  padding: 0;
  position: relative;
}
li {
  position: absolute;
  border: 1px solid #42b983;
  height: 20px;
  width: 150px;
  padding: 5px;
  margin-bottom: 5px;
  color: #42b983;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.0-alpha.2/vue.min.js"></script>
<div id="app">
  <button on-click="changeOrder">
    <span v-if="reverse == -1">△</span>
    <span v-if="reverse == 1">▽</span> Order
  </button>
  <ul>
    <li class="moving-item" v-for="item in items" bind-style="{ top: (item.position * 35) + 'px'}">{{ item.name }}</li>
  </ul>  
</div>

V2内置了:https://v2.vuejs.org/v2/guide/transitions.html#Transition-Modes

查看"列表移动过渡"还有shuffle按钮的例子