Vue源码解析之transition-group/重绘与重排🏆 掘金技术征文|双节特别篇

1,475 阅读3分钟

上篇文章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相关属性触发重绘/重排的情况(好像这几天无法访问,国庆前还能进去)

参考:

blog.csdn.net/galaa2011/a…

juejin.cn/post/684490…