上篇文章Vue源码解析之transition(二)主要分析了实现过渡效果最重要的enter函数及其调用时机。transition-group组件也是与transition组件共用这部分逻辑。
但是transition-group组件针对的是列表类的UI;transition组件是针对单个UI。因此,在官方文档中,是对一个列表使用transition-group,在列表元素个数发生变化的时候,会有保留元素的移动效果。cn.vuejs.org/v2/guide/tr…
beforeMount
这里在组件挂载之前重写了_update方法,在之前的文章(juejin.cn/post/685750…
然而,这里重写了update函数。相当于update了两次,具体逻辑后续再分析。
render
render函数是生成vnode的函数,主要分两部分
第一部分:对新的子节点做处理
1. 列表元素使用的优先级依次为父组件传入的tag数据,transition-group的tag属性,默认为span
2. 读取新的子节点,要求每个子节点都要有key
3. 为每个子节点添加transitionData,这里的transitionData与transition组件类似,为一些过渡类及事件。这些都会在patch过程中careate/activate/remove hook时期触发,同transition组件公共逻辑
第二部分:对旧的子节点处理
1. 更新旧节点的transitionData数据
2. 记录旧节点的位置
3. 利用map来筛选出保留节点(并利用createElement函数创建保留节点元素)与被移除的节点
_update
render函数只是对vnode做一个初步处理,随后会调用_update方法。
1. 调用__patch__方法diff旧的子元素与保留的子元素来强制移除部分元素,并且触发保留元素的过渡效果
2. 再次调用原生_update方法通过__patch__来diff 保留的子元素与新的子元素。
__patch__的过程中会触发updated生命周期函数。
updated
1. 判定:没有保留元素或者moveClass没有transition/animation相关属性直接return
2. 对于多次变更元素,可能会导致上一轮更新的回调函数来不及执行,因此在本轮强制执行
3. 读取保留元素的新位置
4. 根据保留元素的前后位置计算出translate属性的移动值,然后添加css属性,产生移动效果
5. 添加移动效果结束后的回调函数
hasMove
重绘与重排
在一起的文章浏览器相关(一)渲染流程与重排/重绘总结过重绘与重排,在transition-group组件中也涉及到了重绘与重排。
documet.body.offsetHeight
在updated函数中用此属性强制浏览器进行重排
同步布局与保留元素的translate属性添加
原理很简单:通过recordPosition函数读取保留元素的新位置,再通过保留元素前后位置差添加translate属性。
但是是通过分别遍历两次保留元素进行上述操作,并非是读取之后直接添加新元素。否则会触发同步布局,导致性能降低。
最后
transition-goup组件,比较重要的是重写了update函数,每次更新都要update两次。
为何update两次
因为涉及到位置计算,然而vue会尽可能地复用旧节点,因此可能会导致一些旧节点的位置计算可能出错,因此就有了两次update。第一次移除所有需要移除的元素触发其过渡效果;第二次插入需要插入的节点。
注意重绘/重排
推荐一个网站csstriger,里面列举了css相关属性触发重绘/重排的情况(好像这几天无法访问,国庆前还能进去)
参考: