transition-group组件v-move实现原理的一些理解
- 在查看到官方文档的
transition-group
的时候,发现transition-group
组件可以使得整个transition-group
里的li
(或其他元素)都能够准确的移动到他们的正确的位置,并在此期间添加上动画。特别是就算你移除\添加节点也有动画 - 我们知道,在dom里删除\添加节点时,浏览器是直接重绘的,哪里还会给你整个动画?
- 所以我关注的其实就是,vue移除\添加节点时是怎么实现添加动画的
在查看源码后,发现了一点线索,现在整理出来,也算是解决了自己的一点小疑惑。(或许?)
以下属于个人理解,如有错误,欢迎批评指正
< transition-group >源码地址
https://github.com/vuejs/vue/blob/dev/src/platforms/web/runtime/components/transition-group.js
1、实现思路解析:
- 1、在
render()
函数中,发现下面几行代码,不拿发现每次render
都会获取到每个li
(或者其他元素,这里用li
做代表)所对应的的位置(或其他数据)并储存在各自的c.data.pos
中(c
代表这个vnode)
render(){
...
//const c = this.$slots.default || []
//第83行
c.data.pos = c.elm.getBoundingClientRect()
...
}
- 2、接下来,在
updated()
生命周期函数里,通过children.forEach(recordPosition)
来记录我们每个节点的新的位置,并储存在c.data.newPos
中(c
代表这个vnode)
updated(){
...
//第107行
children.forEach(recordPosition)
...
//第175行
function recordPosition (c: VNode) {
c.data.newPos = c.elm.getBoundingClientRect()
}
}
- 3、通过css属性实现从
c.data.pos
到c.data.newPos
的过渡动画,就实现了transition-group
动画,
//第108行
children.forEach(applyTranslation)
//第179行
function applyTranslation (c: VNode) {
const oldPos = c.data.pos
const newPos = c.data.newPos
const dx = oldPos.left - newPos.left
const dy = oldPos.top - newPos.top
if (dx || dy) {
c.data.moved = true
const s = c.elm.style
s.transform = s.WebkitTransform = `translate(${dx}px,${dy}px)`
s.transitionDuration = '0s'
}
}
2、回到我的疑问点
如果在新的页面里,添加或删除了某个节点呢?
- 添加节点时时:
- 由于是新添加的,所以没有
c.data.pos
(初始的css数据),那么就把v-enter
的值赋给c.data.pos
。既然是个新添加的节点并出现在了页面上,那肯定有c.data.newPos
嘛。 - 这样,有了
c.data.pos
和c.data.newPos
,就能在添加节点时实现动画了!
- 由于是新添加的,所以没有
- 删除节点时:
- 由于移除,所以没有了
c.data.newPos
数据,那么把v-leave-to
的值赋给c.data.newPos
- 同上,有了
c.data.pos
和c.data.newPos
,就能在删除节点时实现动画了!
- 由于移除,所以没有了
//c.data.moved 是在updated()中计算并保存的需要移除的节点数组
//第115行
children.forEach((c: VNode) => {
if (c.data.moved) {
//相关操作
}
})