如何使用 Vue.js 动画化列表排序
How to animate the sorting of a list with Vue.js
我正在尝试使用 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
只呈现一次)。然后将您的绑定样式针对您的项目上的新索引参数,如下所示:
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://vuejs.org/v2/guide/transitions.html#Transition-Modes
查看 "List Move Transitions" 和带有随机播放按钮的示例。
我正在尝试使用 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
只呈现一次)。然后将您的绑定样式针对您的项目上的新索引参数,如下所示:
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://vuejs.org/v2/guide/transitions.html#Transition-Modes
查看 "List Move Transitions" 和带有随机播放按钮的示例。