<transition-group>
组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move
class,它会在元素的改变定位的过程中应用。像之前的类名一样,可以通过 name
attribute 来自定义前缀,也可以通过 move-class
attribute 手动设置。
v-move
对于设置过渡的切换时机和过渡曲线非常有用,你会看到如下的例子:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
<div id="flip-list-demo" class="demo">
<button v-on:click="shuffle">Shuffle</button>
<transition-group name="flip-list" tag="ul">
<li v-for="item in items" v-bind:key="item">
{{ item }}
</li>
</transition-group>
</div>
new Vue({
el: ‘#flip-list-demo‘,
data: {
items: [1,2,3,4,5,6,7,8,9]
},
methods: {
shuffle: function () {
this.items = _.shuffle(this.items)//乱序函数
}
}
})
.flip-list-move {
transition: transform 1s;
}
- 3
- 1
- 8
- 6
- 9
- 4
- 5
- 7
- 2
这个看起来很神奇,内部的实现,Vue 使用了一个叫 FLIP 简单的动画队列
使用 transforms 将元素从之前的位置平滑过渡新的位置。
该动画的思路是:
1.标记处未变化前的位置(用getBoundingClientReact);
2.不用动画,立即让元素移动到目标位置,并标记出来变化后的位置;
3.重新移动到原位置,让元素移动到原来的位置;
4动画过渡到新位置;
具体的例子,AB两个元素的交换位置为例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button>change</button> <li>A</li> <li>B</li> <script> var btn = document.getElementsByTagName(‘button‘)[0]; function getTop(dom) { return dom.getBoundingClientRect().top; } function animate(dom, initTop) { var char = initTop - getTop(dom); //获取两个位置的差值 dom.style.transform = `translateY(${char}px)`; //立即变到原来的位置 requestAnimationFrame(() => { requestAnimationFrame(() => { //requestanimationframe是在渲染前执行,所以需要两次后 dom.style.transform = null; dom.style.transition = dom.style.transition = ‘1s‘; dom.addEventListener(‘transitionend‘, function () { dom.style.transition = null; }) }) }) } btn.onclick = function () { var li_1 = document.getElementsByTagName(‘li‘)[0]; var li_2 = document.getElementsByTagName(‘li‘)[1]; var li_1_top = getTop(li_1); var li_2_top = getTop(li_2); document.body.insertBefore(li_2, li_1); animate(li_1, li_1_top); animate(li_2, li_2_top) } </script> </body> </html>