Vue源码之transition-group

我心飞翔 分类:javascript

transition-group组件解析

Function

Vue源码之transition-group
Vue源码之transition-group
Vue源码之transition-group
Vue源码之transition-group
Vue源码之transition-group

工具函数

  • recordPosition
Vue源码之transition-group
  • applyTranslation
Vue源码之transition-group

首次渲染

流程

Vue源码之transition-group

总结

1.执行transition-group的render函数,获取定义的tag,未定义就获取默认值。

2.创建map空对象 ,创建prevChildren数组,创建rawChildren为组件包裹的内容,创建children数组。

3.通过transition-group的属性和事件提取数据赋值给transitionData。

4.遍历rawChildren对节点的key做判断,不存在会报错,存在就把节点push到children中,其次以节点的key为key,节点为value存储到map中。接着设置节点data的transition为transitionData。这点很关键,只有这样才能实现列表中单个元素的过渡动画。

5.最终调用h也就是createElment将children传入渲染tag Vnode。

6.执行updated时,在beforeMount中对_update进行了重写,首先保存之前的_update,首先调用patch此时this._vnode和this.kept为undefined啥也不做 ,然后在调用原始的update函数再次进行patch渲染tag Vnode为DOM节点。

点击add

流程

Vue源码之transition-group

总结

1.执行transition-group的render函数,获取定义的tag,未定义就获取默认值。

2.创建map空对象 ,创建prevChildren数组为上一次渲染的children(9条),创建rawChildren为组件包裹的内容(10条),创建children数组。

3.通过transition-group的属性和事件提取数据赋值给transitionData。

4.遍历rawChildren对节点的key做判断,不存在会报错,存在就把节点push到children中,其次以节点的key为key,节点为value存储到map中。接着设置节点data的transition为transitionData。这点很关键,只有这样才能实现列表中单个元素的过渡动画。

5.此时存在prevChildren,首先创建kept和removed数组。循环prevChildren,把当前的transitionData赋值到上一次每个节点的data的transition属性中,通过原生dom节点api getBoundingClientRect获取到位置数据保留到上一次每个节点的data的pos属性中。

6.如果上次渲染的节点也在这次渲染的节点中,把节点往kept数组里丢。否则把节点往removed数组里丢。调用h也就是createElment将kept传入渲染tag Vnode。保存到this.kept中,把removed数组保存到this.removed中。

7.最终调用h也就是createElment将children传入渲染tag Vnode。

8.执行updated时,在beforeMount中对_update进行了重写,首先保存之前的_update,接着调用patch此时this._vnode为首次渲染的组件vnode(9条),this.kept为tag为p的vnode(9条)两者为相同节点执行patchVnode。然后在调用原始的update函数再次进行patch,此时是旧vnode(9条)与新vnode(10条)的对比,执行patchVnode。this._update执行完成后调用update钩子,执行transition-group的update函数.

9.update函数首先获取prevChildren,然后获取获取move类,通过hasMove函数判断是否存在move类并且css属性是否与缓动相关。

10.接着对prevChildren遍历执行callPendingCbs在前⼀个过渡动画没执⾏完⼜再次执⾏到updated的时候,会提前执⾏ _moveCb 和 _enterCb 确保执行顺序没问题。

11.对prevChildren遍历执行recordPosition记录节点的新位置赋值给节点data的newPos属性。

12.对prevChildren遍历执行applyTranslation先计算节点新位置和旧位置的差值,如果差值不为 0,则说明这些节点是需要移动的,所以记录 vnode.data.moved 为 true,并且通过设置 transform 把需要移动的节点的位置⼜偏移到之前的旧位置,⽬的是为了做move缓动做准备。

13.强制重绘。

14.对prevChildren遍历,对于标志moved的节点,添加move class,移除动画,由于有move class 所以就有了move 的动画,添加transition结束事件 结束后执行cb函数一系列清理操作。

点击remove

流程

Vue源码之transition-group

总结

1.执行transition-group的render函数,获取定义的tag,未定义就获取默认值。

2.创建map空对象 ,创建prevChildren数组为上一次渲染的children(10条),创建rawChildren为组件包裹的内容(8条),创建children数组。

3.通过transition-group的属性和事件提取数据赋值给transitionData。

4.遍历rawChildren对接点的key做判断,不存在会报错,存在就把节点push到children中,其次以节点的key为key,节点为value存储到map中。接着设置节点data的transition为transitionData。这点很关键,只有这样 才能实现列表中单个元素的过渡动画。

5.此时存在prevChildren,首先创建kept和removed数组。循环prevChildren,把当前的transitionData赋值到上一次每个节点的data的transition属性中,通过原生dom节点api getBoundingClientRect获取到位置数据保留到上一次每个节点的data的pos属性中。

6.如果上次渲染的节点也在这次渲染的节点中,把节点往kept数组里丢(8条)。否则把节点往removed数组里丢。调用h也就是createElment将kept传入渲染tag Vnode。保存到this.kept中,把removed数组保存到this.removed中(2条)。

7.最终调用h也就是createElment将children传入渲染tag Vnode。

8.执行updated时,在beforeMount中对_update进行了重写,首先保存之前的_update,调用patch此时this._vnode为上一次渲染的组件vnode(10条子节点),this.kept为tag为p的vnode(8条子节点)两者为相同节点执行patchVnode对比将当前仍存在的标签节点作为新节点,移除当前不存在的节点。然后将this.kept赋值给this._vnode,最后调用原始的update函数再次进行patch,此时是旧vnode也就是this._vnode(8条)与新vnode(8条)的对比,执行patchVnode。this._update执行完成后调用update钩子,执行transition-group的update函数。(两次patch:第一次是从document移除当前不存在的旧节点,因为数据更新过程是不稳定的,第一次调用patch第四个参数为true,那么节点就不会移动。第二次是如果节点有新增的情况添加新节点到document中,完成更新。)

9.update函数首先获取prevChildren,然后获取获取move类,通过hasMove函数判断是否存在move类并且css属性是否与缓动相关。

10.接着对prevChildren遍历执行callPendingCbs在前⼀个过渡动画没执⾏完⼜再次执⾏到updated的时候,会提前执⾏ _moveCb 和 _enterCb 确保执行顺序没问题。

11.对prevChildren遍历执行recordPosition记录节点的新位置赋值给节点data的newPos属性。

12.对prevChildren遍历执行applyTranslation先计算节点新位置和旧位置的差值,如果差值不为 0,则说明这些节点是需要移动的,所以记录 vnode.data.moved 为 true,并且通过设置 transform 把需要移动的节点的位置⼜偏移到之前的旧位置,⽬的是为了做move缓动做准备。

13.强制重绘。

14.对prevChildren遍历,对于标志moved的节点,添加move class,移除动画,由于有move class 所以就有了move 的动画,添加transition结束事件 结束后执行cb函数一系列清理操作。

总结

Vue源码之transition-group

回复

我来回复
  • 暂无回复内容